package com.freemalll.merchant.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.freemalll.common.core.domain.Result;
import com.freemalll.common.core.exception.BusinessException;
import com.freemalll.common.redis.service.RedisService;
import com.freemalll.common.security.utils.SecurityUtils;
import com.freemalll.merchant.constant.CommonConstant;
import com.freemalll.merchant.domain.dto.*;
import com.freemalll.merchant.domain.entity.*;
import com.freemalll.merchant.domain.vo.*;
import com.freemalll.merchant.common.CommonEnum;
import com.freemalll.merchant.common.Constant;
import com.freemalll.merchant.domain.dto.merchantParameters.MerParamsDetailDTO;
import com.freemalll.merchant.domain.vo.merchantParameters.MerParamsDetailVO;
import com.freemalll.merchant.feign.BaseFeignService;
import com.freemalll.merchant.mapper.CollaborationApplyMapper;
import com.freemalll.merchant.service.*;
import com.freemalll.merchant.service.coopManagement.MerAssetRateManageDetailService;
import com.freemalll.merchant.service.coopManagement.MerAssetRateManageService;
import com.freemalll.merchant.service.merchantAuditManage.MerAuthFlowLogService;
import com.freemalll.merchant.service.merchantAuditManage.MerAuthFlowService;
import com.freemalll.merchant.service.merchantAuditManage.MerMerchantAuditEditLogService;
import com.freemalll.merchant.utils.*;
import com.freemalll.system.api.model.LoginUser;
import com.freemalll.system.api.model.UserDto;
import com.freemalll.system.api.service.RemoteRoleService;
import com.freemalll.system.api.service.RemoteUserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * @author songshixiong
 * @ClassName CollaborationApplyServiceImpl
 * @description:
 * @date 2025年05月14日
 * @version: 1.0
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class CollaborationApplyServiceImpl implements CollaborationApplyService {

    @Resource
    private FaceHelperService faceHelperService;
    @Resource
    private AddressUtil addressUtil;
    @Resource
    private AliOSSUtil aliOSSUtil;
    @Resource
    private QxbService qxbService;
    @Resource
    private MerMerchantService merMerchantService;
    @Resource
    private MerLicenseService merLicenseService;
    @Resource
    private MerLegalInfoService merLegalInfoService;
    private final Random random = new Random();
    @Resource
    private CollaborationApplyMapper collaborationApplyMapper;
    @Resource
    private MerMedicalLicenseService merMedicalLicenseService;
    @Resource
    private MerVenueInfoService merVenueInfoService;
    @Resource
    private MerAccountLicenseService merAccountLicenseService;
    @Resource
    private MerMerchantRegisterStepService merMerchantRegisterStepService;
    @Resource
    private MerRunInfoService merRunInfoService;
    @Resource
    private MerAttachService merAttachService;
    @Resource
    private MerAttachValueService merAttachValueService;
    @Resource
    private MerInstallmentInfoService merInstallmentInfoService;
    @Resource
    private MerInstallmentInfoCompetitiveService merInstallmentInfoCompetitiveService;
    @Resource
    private MerBankCardService merBankCardService;
    @Resource
    private MerMerchantCapitalOrderService merMerchantCapitalOrderService;
    @Resource
    private MerMerchantRateManageService merMerchantRateManageService;
    @Resource
    private MerAuthFlowService merAuthFlowService;
    @Resource
    private MerAuthFlowLogService merAuthFlowLogService;
    @Resource
    private MerParamsService merParamsService;
    @Resource
    private RiskEgService riskEgService;
    @Resource
    private MerMedicalEduLicenseService merMedicalEduLicenseService;
    @Resource
    private MerMedicalEduIcpLicenseService merMedicalEduIcpLicenseService;
    @Resource
    private MerAttachConfigService merAttachConfigService;
    @Resource
    private HistoryDiffUtils historyDiffUtils;
    @Resource
    private MerMerchantAuditEditLogService merMerchantAuditEditLogService;
    @Resource
    private DateUtil dateUtil;
    @Resource
    private RedisService redisService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private MerMerchantRateManageDetailService merMerchantRateManageDetailService;
    @Value("${residentRoleID}")
    private String residentRoleID;
    @Value("${cityManagerRoleID}")
    private String cityManagerRoleID;
    @Resource
    private MerAssetRateManageService merAssetRateManageService;
    @Resource
    private MerAssetRateManageDetailService merAssetRateManageDetailService;
    @Resource
    private MerMerchantRiskCapitalOrderService merMerchantRiskCapitalOrderService;
    @Resource
    private RemoteRoleService remoteRoleService;
    @Resource
    private RemoteUserService remoteUserService;

    public static final String RESULT = "result";

    @Override
    public List<UserDto> getResidentPersonnel() {
        return getAccountListByRoleId(Arrays.asList(cityManagerRoleID, residentRoleID));
    }

    @Override
    public SubmitPreliminaryReviewResultVo submitPreliminaryReview(SubmitPreliminaryReviewDto dto) {
        if (Objects.isNull(dto) || !StringUtils.hasText(dto.getSubmitType())) {
            throw BusinessException.businessParamsNotExist("参数错误");
        }
        SubmitPreliminaryReviewResultVo vo = new SubmitPreliminaryReviewResultVo();
        //全量保存
        if (Objects.equals(CommonEnum.typeOfCooperationApplicationModule.SAVE.name(), dto.getSubmitType())) {
            savePreliminaryReview(dto, vo);
            //待提交初审
            updateMerchantAuditStatus(MerchantAuditStatusDto.builder()
                    .merId(dto.getMerId())
                    .auditStatus(CommonEnum.auditType.SUBMIT_INITIAL_REVIEW.name())
                    .reexamineFlag(false)
                    .submitPreliminaryReviewFlag(false)
                    .build());
            vo.setAuthStatus(CommonEnum.auditType.SUBMIT_INITIAL_REVIEW.name());
            //生成步骤
            this.createRegisterStep(dto, null);
        }
        //提交初审
        if (Objects.equals(CommonEnum.typeOfCooperationApplicationModule.SUBMIT_AUDIT.name(), dto.getSubmitType())) {
            //1、保存场景信息
            this.savePreliminaryReview(dto, vo);
            //2、请求引擎获取初审结果
            JSONObject result = riskEgService.submitRiskEg(dto.getMerId(), CommonEnum.riskControlEngineType.SUBMIT_PRELIMINARY_REVIEW);
            if (result == null) {
                throw BusinessException.businessParamsNotExist("引擎返回结果为空");
            }
            //更新审核状态
            updateMerchantAuditStatus(MerchantAuditStatusDto.builder()
                    .merId(dto.getMerId())
                    .auditStatus(result.getString("auditResult"))
                    .auditReason(result.getString("reason"))
                    .reexamineFlag(false)
                    .submitPreliminaryReviewFlag(true)
                    .build());
            //3、生成步骤并根据引擎结果设置当前步骤是否完成
            this.createRegisterStep(dto, result.getString("auditResult"));
            //4、回显前端参数
            vo.setAuthStatus(result.getString("auditResult"));
            vo.setReason(result.getString("reason") == null ? "" : result.getString("reason"));
        }
        return vo;
    }

    /**
     * 更新商户审核状态
     *
     * @param dto
     */
    private void updateMerchantAuditStatus(MerchantAuditStatusDto dto) {
        //1、校验审核状态是否存在
        if (Objects.isNull(merMerchantService.getById(dto.getMerId()))) {
            throw BusinessException.businessParamsNotExist("商户信息不存在");
        }
        //2、获取或创建审核流程记录
        MerAuthFlow authFlow = getOrCreateAuthFlow(dto);
        //3、更新审核状态并记录日志
        updateAndLogAuthFlow(authFlow, dto);
    }


    private MerAuthFlow getOrCreateAuthFlow(MerchantAuditStatusDto dto) {
        MerAuthFlow old = merAuthFlowService.getOne(Wrappers.<MerAuthFlow>lambdaQuery().eq(MerAuthFlow::getMerId, dto.getMerId()));
        if (old == null) {
            old = new MerAuthFlow();
            old.setMerId(dto.getMerId());
            old.setAuthStatus(dto.getAuditStatus());
            old.setAuditType(dto.getAuditType());
            old.setRemarks(dto.getAuditReason());
            merAuthFlowService.save(old);
        }
        return old;
    }

    private void updateAndLogAuthFlow(MerAuthFlow authFlow, MerchantAuditStatusDto dto) {
        String lastAuthStatus = authFlow.getAuthStatus();

        // 更新状态
        authFlow.setAuthStatus(dto.getAuditStatus());
        //提交复审更新申请时间
        if (dto.isReexamineFlag()) {
            authFlow.setApplyTime(LocalDateTime.now());
            authFlow.setAuditType(dto.getAuditType());
        }
        //提交初审更新审核时间
        if (dto.isSubmitPreliminaryReviewFlag()) {
            authFlow.setAuthEndDate(LocalDateTime.now());
            authFlow.setCurrentAuthDate(LocalDateTime.now());
        }
        // 保存状态变更
        merAuthFlowService.updateById(authFlow);

        // 记录日志
        MerAuthFlowLog log = new MerAuthFlowLog();
        log.setFlowId(authFlow.getFlowId());
        log.setLastAuthStatus(lastAuthStatus);
        log.setAuthRemark(dto.getAuditReason());
        saveAuthFlowLog(dto.getAuditStatus(), log, dto.getAuditReason());
    }

    private void saveAuthFlowLog(String auditStatus, MerAuthFlowLog log, String auditReason) {
        log.setAuthStatus(auditStatus);
        log.setAuthManId(SecurityUtils.getUserId());
        log.setAuthMan(SecurityUtils.getUsername());
        log.setAuthDate(LocalDateTime.now());
        if (!StringUtils.hasText(auditReason)) {
            CommonEnum.auditType type = CommonEnum.auditType.fromDescription(auditStatus);
            if (type != null) {
                log.setAuthRemark(type.getDescription());
            }
        } else {
            log.setAuthRemark(auditReason);
        }

        merAuthFlowLogService.save(log);
    }


    private void createRegisterStep(SubmitPreliminaryReviewDto dto, String auditResult) {
        List<MerMerchantRegisterStep> list = merMerchantRegisterStepService.list(Wrappers.<MerMerchantRegisterStep>lambdaQuery().eq(MerMerchantRegisterStep::getMerId, dto.getMerId()));
        if (!CollectionUtils.isEmpty(list)) {
            //存在步骤则代表已保存过数据 则直接修改步骤
            for (MerMerchantRegisterStep step : list) {
                if (StringUtils.hasText(auditResult) && CommonEnum.auditType.INITIAL_REVIEW_PASSED.name().equals(auditResult)) {
                    if (step.getStepType().equals(CommonEnum.cooperationApplyStepType.SUBMIT_PRELIMINARY_REVIEW.name())) {
                        step.setCompleteFlag(true);
                        step.setSubmitTime(LocalDateTime.now());
                        step.setCurrentFlag(false);
                        merMerchantRegisterStepService.updateById(step);
                    }
                    if (step.getStepType().equals(CommonEnum.cooperationApplyStepType.LICENSE_INFORMATION.name())) {
                        step.setCurrentFlag(true);
                        merMerchantRegisterStepService.updateById(step);
                    }
                }
            }
        } else {
            //创建步骤
            List<RegisterStepDto> registerStepDtoList = dto.getRegisterStepList();
            //第一步初始化生成步骤
            for (int i = 0; i < registerStepDtoList.size(); i++) {
                RegisterStepDto registerStepDto = registerStepDtoList.get(i);
                //是否完成
                if (StringUtils.hasText(auditResult) && CommonEnum.auditType.INITIAL_REVIEW_PASSED.name().equals(auditResult)) {
                    if (CommonEnum.cooperationApplyStepType.SUBMIT_PRELIMINARY_REVIEW == registerStepDto.getStepType()) {
                        registerStepDto.setCompleteFlag(true);
                        registerStepDto.setCurrentFlag(false);
                        registerStepDto.setSubmitTime(LocalDateTime.now());
                    }
                    if (CommonEnum.cooperationApplyStepType.LICENSE_INFORMATION == registerStepDto.getStepType()) {
                        registerStepDto.setCurrentFlag(true);
                    }
                }
                merMerchantRegisterStepService.save(MerMerchantRegisterStep.builder()
                        .merId(dto.getMerId())
                        .stepName(registerStepDto.getStepName())
                        .stepType(registerStepDto.getStepType().name())
                        .completeFlag(registerStepDto.getCompleteFlag())
                        .currentFlag(registerStepDto.getCurrentFlag())
                        .submitTime(registerStepDto.getSubmitTime())
                        .orderNo(i + 1)
                        .build());
            }
        }
    }

    private void savePreliminaryReview(SubmitPreliminaryReviewDto dto, SubmitPreliminaryReviewResultVo vo) {
        //校验业务参数
        checkBusinessParams(dto);
        //校验商户名称/简称/营业执照编码
        merLicenseService.checkMerchant(dto.getBusinessLicenseDto().getLicenseCode(), dto.getBusinessLicenseDto().getLicenseName(), dto.getBusinessLicenseDto().getLicenseShortName(), false, dto.getMerId());
        merLicenseService.checkLicenseCode(dto.getBusinessLicenseDto().getLicenseCode(), dto.getBusinessLicenseDto().getLicenseName(), dto.getBusinessLicenseDto().getLicenseShortName(), false, dto.getMerId());
        //更新场景信息,如果是新增则将生成的merId放入dto中，通过dto传递给下面的方法建立与商户表的关联关系
        String applyCode = saveSceneInfo(dto);
        //保存初审信息
        saveInitialReviewInfo(dto);
        //保存营业执照
        saveBusinessLicense(dto.getBusinessLicenseDto(), dto.getMerId());
        //保存法人信息
        saveCorporateInfo(dto.getCorporateInfoDto(), dto.getMerId());
        //保存场地信息
        saveVenueInfo(dto.getInitialReviewInfoDto().getVenueArea(), dto.getMerId());
        vo.setApplyCode(applyCode);
        vo.setMerId(dto.getMerId());
    }

    private void checkBusinessParams(SubmitPreliminaryReviewDto dto) {
        //法人身份证和营业执照法人身份证名称必须一致
        if (!Objects.equals(dto.getBusinessLicenseDto().getLicenseLegalMan(), dto.getCorporateInfoDto().getLegalMan())) {
            throw BusinessException.businessValidateError("法人身份证信息与营业执照法人信息不一致");
        }
    }

    private void saveVenueInfo(Double venueArea, String merId) {
        MerVenueInfo venueInfo = merVenueInfoService.getOne(Wrappers.<MerVenueInfo>lambdaQuery().eq(MerVenueInfo::getMerId, merId));
        if (venueInfo == null) {
            venueInfo = new MerVenueInfo();
        }
        venueInfo.setMerId(merId);
        venueInfo.setVenueArea(venueArea);
        merVenueInfoService.saveOrUpdate(venueInfo);
    }

    private String generateApplicationCode(String licenseProvince, String sceneCategory) {
        //MAR+两位场景编码（01代表大健康，02代表教育）+两位省份编码+年月日+三位自然数
        if (sceneCategory.equals(CommonEnum.sceneCategory.DJK.name())) {
            sceneCategory = "01";
        }
        if (sceneCategory.equals(CommonEnum.sceneCategory.JY.name())) {
            sceneCategory = "02";
        }
        licenseProvince = licenseProvince.substring(0, 2);
        return "MAR" + sceneCategory + licenseProvince + dateUtil.getCurrentDate() + String.format("%03d", random.nextInt(900) + 100);
    }


    /**
     * 保存法人信息
     *
     * @param dto
     * @param merId
     */
    private void saveCorporateInfo(CorporateInfoDto dto, String merId) {
        if (!StringUtils.hasText(dto.getLegalIdCardFront())) {
            throw BusinessException.businessValidateError("法人身份证正面地址不能为空");
        }
        if (!StringUtils.hasText(dto.getLegalIdCardBack())) {
            throw BusinessException.businessValidateError("法人身份证反面地址不能为空");
        }
        MerLegalInfo merLegalInfo = merLegalInfoService.getOne(Wrappers.<MerLegalInfo>lambdaQuery().eq(MerLegalInfo::getMerId, merId));
        if (merLegalInfo == null) {
            merLegalInfo = new MerLegalInfo();
        }
        if (StringUtils.hasText(dto.getLegalValidateStart())) {
            LocalDate startTime = LocalDate.parse(dto.getLegalValidateStart());
            LocalDate now = LocalDate.now();
            if (startTime.isAfter(now)) {
                throw BusinessException.businessValidateError("法人身份证有效期开始日期不能大于今天");
            }
        }
        if (StringUtils.hasText(dto.getLegalValidateEnd()) && !Objects.equals("长期", dto.getLegalValidateEnd())) {
            LocalDate endTime = LocalDate.parse(dto.getLegalValidateEnd());
            LocalDate now = LocalDate.now();
            if (endTime.isBefore(now)) {
                throw BusinessException.businessValidateError("法人身份证有限期结束日期不能小于今天");
            }
        }
        BeanUtils.copyPropertiesIgnoreNull(dto, merLegalInfo);
        merLegalInfo.setMerId(merId);
        merLegalInfoService.saveOrUpdate(merLegalInfo);
        //保存附件 法人身份证正面地址
        merAttachService.edit(merId, dto.getLegalIdCardFront(), CommonEnum.businessPhotoType.legal_id_card_front, 1);
        //法人身份证反面地址
        merAttachService.edit(merId, dto.getLegalIdCardBack(), CommonEnum.businessPhotoType.legal_id_card_back, 1);

    }

    /**
     * 营业执照保存
     *
     * @param dto
     * @param merId
     */
    private void saveBusinessLicense(BusinessLicenseDto dto, String merId) {
        if (!StringUtils.hasText(dto.getLicenseImage())) {
            throw BusinessException.businessValidateError("请上传营业执照图片");
        }
        MerLicense merLicense = merLicenseService.getOne(Wrappers.<MerLicense>lambdaQuery().eq(MerLicense::getMerId, merId));
        if (Objects.isNull(merLicense)) {
            merLicense = new MerLicense();
        }
        //校验有效期
        if (StringUtils.hasText(dto.getLicenseValidateStart())) {
            LocalDate startTime = LocalDate.parse(dto.getLicenseValidateStart());
            LocalDate now = LocalDate.now();
            if (startTime.isAfter(now)) {
                throw BusinessException.businessValidateError("营业执照开始日期不能大于今天");
            }
        }
        if (StringUtils.hasText(dto.getLicenseValidateEnd()) && !Objects.equals("长期", dto.getLicenseValidateEnd())) {
            LocalDate endTime = LocalDate.parse(dto.getLicenseValidateEnd());
            LocalDate now = LocalDate.now();
            if (endTime.isBefore(now)) {
                throw BusinessException.businessValidateError("营业执照结束日期不能小于今天");
            }
        }
        //有效期起不能小于成立日期
        if (StringUtils.hasText(dto.getLicenseRegisterDate()) && StringUtils.hasText(dto.getLicenseValidateStart())) {
            LocalDate establishTime = LocalDate.parse(dto.getLicenseRegisterDate());
            LocalDate startTime = LocalDate.parse(dto.getLicenseValidateStart());
            if (establishTime.isAfter(startTime)) {
                throw BusinessException.businessValidateError("营业执照有效期开始日期不能小于成立日期");
            }
        }
        merLicense.setMerId(merId);
        BeanUtils.copyPropertiesIgnoreNull(dto, merLicense);
        merLicenseService.saveOrUpdate(merLicense);
        //保存或修改附件
        merAttachService.edit(merId, dto.getLicenseImage(), CommonEnum.businessPhotoType.business_license, 1);
    }

    /**
     * 保存初审信息
     *
     * @param dto
     */
    private void saveInitialReviewInfo(SubmitPreliminaryReviewDto dto) {
        MerMerchant merMerchantSupplement = new MerMerchant();
        if (StringUtils.hasText(dto.getMerId())) {
            merMerchantSupplement = merMerchantService.getById(dto.getMerId());
        }
        SceneInfoVoDto sceneInfoDto = dto.getSceneInfoDto();
        InitialReviewInfoDto reviewInfoDto = dto.getInitialReviewInfoDto();
        //场景父类别
        merMerchantSupplement.setSceneParentCategory(sceneInfoDto.getSceneParentCategory());
        //场景类别
        merMerchantSupplement.setSceneCategory(sceneInfoDto.getSceneCategory());
        //商户模式
        merMerchantSupplement.setMerModel(sceneInfoDto.getMerModel());
        //申请类型
        merMerchantSupplement.setApplyType(reviewInfoDto.getApplyType());
        //门店类型
        merMerchantSupplement.setStoreType(reviewInfoDto.getStoreType());
        //关联商户id
        merMerchantSupplement.setRelatedMerId(reviewInfoDto.getRelatedMerId());
        //品牌类型
        merMerchantSupplement.setBrandType(reviewInfoDto.getBrandType());
        //品牌名称
        merMerchantSupplement.setBrandName(reviewInfoDto.getBrandName());
        // 品牌名称非空时需要去校验参数管理-品牌库是否具有该品牌，如果没有则需要新增
        merParamsService.checkAndAddBrand(reviewInfoDto.getBrandName());
        //特殊申请
        merMerchantSupplement.setSpecialApply(reviewInfoDto.getSpecialApply());
        //申请政策 多选逗号隔开
        merMerchantSupplement.setApplyPolicy(reviewInfoDto.getApplyPolicy());
        //申请说明
        merMerchantSupplement.setApplyDesc(reviewInfoDto.getApplyDesc());
        merMerchantService.saveOrUpdate(merMerchantSupplement);
    }

    /**
     * 更新场景信息
     *
     * @param dto
     */
    private String saveSceneInfo(SubmitPreliminaryReviewDto dto) {
        MerMerchant merMerchant = new MerMerchant();
        if (StringUtils.hasText(dto.getMerId())) {
            merMerchant = merMerchantService.getById(dto.getMerId());
        }
        if (!StringUtils.hasText(merMerchant.getApplyCode())) {
            //生成申请编码
            String applicationCode = generateApplicationCode(dto.getBusinessLicenseDto().getLicenseProvince(), dto.getSceneInfoDto().getSceneParentCategory());
            merMerchant.setApplyCode(applicationCode);
        }
        SceneInfoVoDto sceneInfoDto = dto.getSceneInfoDto();
        BusinessLicenseDto businessLicenseDto = dto.getBusinessLicenseDto();
        //流量商户
        merMerchant.setTrafficMerchant(sceneInfoDto.getTrafficMerchant());
        //驻点
        merMerchant.setSalePersons(sceneInfoDto.getSalePersons());
        //商户简称
        merMerchant.setMerShortName(businessLicenseDto.getLicenseShortName());
        //商户名称
        merMerchant.setMerName(businessLicenseDto.getLicenseName());
        //商户拼音
        merMerchant.setPinyin(PinyinUtil.convertToPinyin(businessLicenseDto.getLicenseName()));
        //设置入驻时间
        merMerchant.setCreateDate(dto.getCreateDate());
        //获客方式
        merMerchant.setCustomerAcquisitionMethod(sceneInfoDto.getCustomerAcquisitionMethod());
        //设置oa编码
        LoginUser loginUser = SecurityUtils.getLoginUser();
        merMerchant.setOaCode(
                Optional.ofNullable(loginUser)
                        .map(LoginUser::getUserDto)
                        .map(UserDto::getOaCode)
                        .orElse("")
        );
        merMerchantService.saveOrUpdate(merMerchant);
        dto.setMerId(merMerchant.getMerId());
        return merMerchant.getApplyCode();
    }


    @Override
    public IdCardOrcVo idCardOcr(MultipartFile file) {
        if (file == null) {
            throw BusinessException.businessParamsNotExist("请先上传身份证文件");
        }
        try {
            JSONObject jsonObject = faceHelperService.ocrIdCard(file.getInputStream());
            if (jsonObject == null) {
                throw BusinessException.businessParamsNotExist("ocr识别错误：识别结果为空");
            }
            IdCardOrcVo idCardOrcVo = new IdCardOrcVo();
            String side = jsonObject.getString("side");
            idCardOrcVo.setSide(side);
            if ("0".equals(side)) {
                //姓名
                idCardOrcVo.setLegalMan(jsonObject.getJSONObject("name").getString(RESULT));
                //身份证号
                idCardOrcVo.setLegalManIdCard(jsonObject.getJSONObject("idcard_number").getString(RESULT));
                //出生日期
                idCardOrcVo.setBirthday(dateUtil.formatBirthDate(jsonObject.getJSONObject("birth_year").getString(RESULT), jsonObject.getJSONObject("birth_month").getString(RESULT), jsonObject.getJSONObject("birth_day").getString(RESULT)));
                //民族
                idCardOrcVo.setNationality(jsonObject.getJSONObject("nationality").getString(RESULT));
                //地址
                String string = jsonObject.getJSONObject("address").getString(RESULT);
                //地址解析成省市区详细地址
                DTOAddress address = addressUtil.addressTrans(string);
                if (address == null) {
                    return idCardOrcVo;
                }
                //地址
                idCardOrcVo.setLegalManProvince(address.getProvince());
                idCardOrcVo.setLegalManCity(address.getCity());
                idCardOrcVo.setLegalManCountry(address.getCounty());
                idCardOrcVo.setLegalManAddress(address.getStreet());
                idCardOrcVo.setProvinceCode(address.getProviceCode());
                idCardOrcVo.setCityCode(address.getCityCode());
                idCardOrcVo.setCountryCode(address.getCountyCode());
            } else {
                //国徽面 获取身份证有效期 起
                idCardOrcVo.setLegalValidateStart(dateFormatConversion(jsonObject.getJSONObject("valid_date_start").getString(RESULT)));
                //身份证有效期止
                idCardOrcVo.setLegalValidateEnd(dateFormatConversion(jsonObject.getJSONObject("valid_date_end").getString(RESULT)));
            }
            return idCardOrcVo;
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            log.error("ocr识别错误：{} ", e.getMessage());
            throw BusinessException.businessParamsNotExist("OCR识别失败，请手动输入或重新识别");
        }
    }


    @Override
    public BusinessLicenseVo businessLicenseOcr(MultipartFile file) {
        if (file == null) {
            throw BusinessException.businessParamsNotExist("请先上传营业执照文件");
        }
        try {
            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null || originalFilename.isEmpty()) {
                throw BusinessException.businessParamsNotExist("请先上传营业执照文件");
            }
            String fileType = originalFilename.substring(file.getOriginalFilename().lastIndexOf("."));
            InputStream is = file.getInputStream();
            String imagePath = aliOSSUtil.uploadFile(is, "merchant/license", dateUtil.getDateStr(LocalDate.now()) + "_" + random.nextInt(9999) + fileType);// 单个上传外网地址
            String aliOSSImagePath = aliOSSUtil.getFileUrl(imagePath);
            BusinessLicenseVo vo = new BusinessLicenseVo();
            JSONObject result = faceHelperService.ocrBusinessLicense(aliOSSImagePath);
            if (result == null) {
                throw BusinessException.businessParamsNotExist("营业执照ocr识别错误：识别结果为空");
            }
            if (result.getInteger("code") != 200) {
                throw BusinessException.businessParamsNotExist(result.getString("msg"));
            }
            JSONObject jsonObject = result.getJSONObject("data").getJSONObject("data");
            if (jsonObject == null) {
                throw BusinessException.businessParamsNotExist("营业执照ocr识别错误：识别结果为空");
            }
            //信用代码
            vo.setLicenseCode(jsonObject.getString("creditCode"));
            //商户名称
            vo.setLicenseName(jsonObject.getString("companyName"));
            //法人代表
            vo.setLicenseLegalMan(jsonObject.getString("legalPerson"));
            //注册资本
            String registeredCapital = jsonObject.getString("registeredCapital");
            //中文数字转化为阿拉伯数字
            if (StringUtils.hasText(registeredCapital)) {
                String[] split = registeredCapital.split("万元");
                if (split.length > 0) {
                    String chinaNum = split[0];
                    long arabicNum = CommonUtil.ChineseToArabicConverter(chinaNum);
                    vo.setLicenseCapital(BigDecimal.valueOf(arabicNum));
                }
            }
            //工商类型
            vo.setLicenseType(jsonObject.getString("companyType"));
            //营业执照成立日期
            vo.setLicenseRegisterDate(dateFormatConversion(jsonObject.getString("validFromDate")));
            //有效期起
            vo.setLicenseValidateStart(dateFormatConversion(jsonObject.getString("validFromDate")));
            //有效期止 ocr没返回值则直接设置为9999-12-31，否则设置为ocr识别结果
            if (!StringUtils.hasText(jsonObject.getString("validToDate"))) {
                vo.setLicenseValidateEnd("9999-12-31");
            } else {
                vo.setLicenseValidateEnd(dateFormatConversion(jsonObject.getString("validToDate")));
            }
            //经营范围
            vo.setLicenseRunRange(jsonObject.getString("businessScope"));
            //注册地址
            if (jsonObject.get("businessAddress") != null) {
                String address = jsonObject.getString("businessAddress");
                if (StringUtils.hasText(address)) {
                    DTOAddress dtoAddress = addressUtil.addressTrans(address);
                    if (dtoAddress == null) {
                        return vo;
                    }
                    vo.setLicenseProvince(dtoAddress.getProvince());
                    vo.setLicenseCity(dtoAddress.getCity());
                    vo.setLicenseCountry(dtoAddress.getCounty());
                    vo.setLicenseAddress(dtoAddress.getStreet());
                    vo.setProvinceCode(dtoAddress.getProviceCode());
                    vo.setCityCode(dtoAddress.getCityCode());
                    vo.setCountryCode(dtoAddress.getCountyCode());
                }
            }
            merLicenseService.checkMerchant(vo.getLicenseCode(), vo.getLicenseName(), null, false, null);
            merLicenseService.checkLicenseCode(vo.getLicenseCode(), vo.getLicenseName(), null, false, null);
            return vo;
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            log.error("营业执照ocr识别错误：{} ", e.getMessage());
            throw BusinessException.businessParamsNotExist("OCR识别失败，请手动输入或重新识别");
        }
    }

    @Override
    public MerAccountLicenseVo accountLicenseOcr(MultipartFile file) {
        if (file == null) {
            throw BusinessException.businessParamsNotExist("请先上传文件");
        }
        try {
            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null || originalFilename.isEmpty()) {
                throw BusinessException.businessParamsNotExist("请先上传文件");
            }
            String fileType = originalFilename.substring(file.getOriginalFilename().lastIndexOf("."));
            InputStream is = file.getInputStream();
            String imagePath = aliOSSUtil.uploadFile(is, "merchant/account", dateUtil.getDateStr(LocalDate.now()) + "_" + random.nextInt(9999) + fileType);// 单个上传外网地址
            String aliOSSImagePath = aliOSSUtil.getFileUrl(imagePath);
            MerAccountLicenseVo vo = new MerAccountLicenseVo();
            JSONObject result = faceHelperService.ocrBankAccount(aliOSSImagePath);
            if (result == null) {
                throw BusinessException.businessParamsNotExist("银行开户许可证ocr识别错误：识别结果为空");
            }
            if (result.getInteger("code") != 200) {
                throw BusinessException.businessParamsNotExist("银行开户许可证ocr识别错误：识别错误");
            }
            JSONObject jsonObject = result.getJSONObject("data").getJSONObject("data");
            if (jsonObject == null) {
                throw BusinessException.businessParamsNotExist("银行开户许可证ocr识别错误：识别结果为空");
            }
            //账户名称
            vo.setAcclName(jsonObject.getString("customerName"));
            //开户账号
            vo.setAcclBankNo(jsonObject.getString("bankAccount"));
            //法人
            vo.setAcclLegalMan(jsonObject.getString("legalRepresentative"));
            //开户银行
            vo.setAcclBankName(jsonObject.getString("depositaryBank"));
            //账户编码
            vo.setAcclCode(jsonObject.getString("approvalNumber"));
            return vo;
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            log.error("银行开户许可证文件ocr识别错误：{} ", e.getMessage());
            throw BusinessException.businessParamsNotExist("OCR识别失败，请手动输入或重新识别");
        }
    }

    @Override
    public MerBusinessLicenseVo getMerAccountLicense(String licenseCode) throws Exception {
        //todo 测试环境不启用
        throw BusinessException.businessParamsNotExist("测试环境不启用");
//        String bizQxbInfo = qxbService.getBizQxbInfo(licenseCode);
//        if (!StringUtils.hasText(bizQxbInfo)) {
//            throw BusinessException.businessDataNotExist("查询不到该商户的营业执照信息");
//        }
//        JSONObject response = JSON.parseObject(bizQxbInfo);
//        if (response.getInteger("code") != 200) {
//            throw BusinessException.businessDataNotExist("查询不到该商户的营业执照信息");
//        }
//        JSONObject data = response.getJSONObject("data");
//        if (data.getInteger("status") != 200) {
//            throw BusinessException.businessDataNotExist(data.getString("message"));
//        }
//        JSONObject jsonObject = data.getJSONObject("data");
//        //转换
//        MerBusinessLicenseVo vo = new MerBusinessLicenseVo();
//        //信用代码
//        vo.setLicenseCode(licenseCode);
//        //商户名称
//        vo.setLicenseName(jsonObject.getString("format_name"));
//        //法人代表
//        vo.setLicenseLegalMan(jsonObject.getString("operName"));
//        //注册资本
//        String registCapi = conversionAmount(jsonObject.getString("registCapi"));
//        if (registCapi != null) {
//            vo.setLicenseCapital(new BigDecimal(registCapi));
//        }
//        //工商类型
//        vo.setLicenseType(jsonObject.getString("econKind"));
//        //成立日期
//        vo.setLicenseRegisterDate(jsonObject.getString("startDate"));
//        //经营范围
//        vo.setLicenseRunRange(jsonObject.getString("scope"));
//        //注册地址
//        if (StringUtils.hasText(jsonObject.getString("address"))) {
//            DTOAddress dtoAddress = addressUtil.addressTrans(jsonObject.getString("address"), "1");
//            if (dtoAddress == null) {
//                return vo;
//            }
//            vo.setLicenseProvince(dtoAddress.getProvince());
//            vo.setLicenseCity(dtoAddress.getCity());
//            vo.setLicenseCountry(dtoAddress.getCounty());
//            vo.setLicenseAddress(dtoAddress.getStreet());
//            vo.setProvinceCode(dtoAddress.getProviceCode());
//            vo.setCityCode(dtoAddress.getCityCode());
//            vo.setCountryCode(dtoAddress.getCountyCode());
//        }
//        return vo;
    }

    @Override
    public MerchantInfoVo getMerInfoById(String merId) {
        MerchantInfoVo vo = new MerchantInfoVo();
        //查步骤
        List<RegisterStepDto> registerSteps = merMerchantRegisterStepService.listByMerId(merId);
        vo.setRegisterStepList(registerSteps);
        //查申请编码
        MerMerchant merchant = merMerchantService.getById(merId);
        vo.setApplyCode(merchant.getApplyCode());
        vo.setCreateDate(merchant.getCreateDate());
        vo.setSceneCategory(merchant.getSceneCategory());
        vo.setSceneParentCategory(merchant.getSceneParentCategory());
        //初审
        getSubmitPreliminaryReview(vo, merId);
        //获取商户当前状态
        MerAuthFlow merAuthFlow = merAuthFlowService.getOne(Wrappers.<MerAuthFlow>lambdaQuery().eq(MerAuthFlow::getMerId, merId));
        vo.setAuthStatus(merAuthFlow.getAuthStatus());
        //初审退回、初审拒绝 从remarks中取备注
        if (Arrays.asList(CommonEnum.auditType.INITIAL_REVIEW_RETURNED.name(), CommonEnum.auditType.INITIAL_REVIEW_REFUSED.name()).contains(merAuthFlow.getAuthStatus())) {
            vo.setReason(merAuthFlow.getRemarks());
        }
        //复审拒绝、复审退回 从refused_reason中取
        if (Arrays.asList(CommonEnum.auditType.REVIEW_REFUSED.name(), CommonEnum.auditType.REVIEW_RETURNED.name()).contains(merAuthFlow.getAuthStatus())) {
            if (StringUtils.hasText(merAuthFlow.getRefusedRemark())) {
                vo.setReason(merParamsService.translateParamKeys(merAuthFlow.getRefusedReason()) + "-" + merAuthFlow.getRefusedRemark());
            } else {
                vo.setReason(merParamsService.translateParamKeys(merAuthFlow.getRefusedReason()));
            }
        }
        //校验条件：是否已存在重新申请商户
        if (!StringUtils.hasText(merchant.getReapplyRelatedMerId())) {
            //初审退回、复审退回、取消申请 重新申请按钮显示为true
            if (Arrays.asList(CommonEnum.auditType.INITIAL_REVIEW_RETURNED.name(), CommonEnum.auditType.REVIEW_RETURNED.name(), CommonEnum.auditType.WITHDRAW.name()).contains(merAuthFlow.getAuthStatus())) {
                vo.setReapplyBtnShowFlag(true);
            }
            //初审拒绝、复审拒绝 重新申请按钮需要判断是否在禁止重新提交天数内
            if (Arrays.asList(CommonEnum.auditType.INITIAL_REVIEW_REFUSED.name(), CommonEnum.auditType.REVIEW_REFUSED.name()).contains(merAuthFlow.getAuthStatus())
                    && !merLicenseService.checkMerchantApplyBtnFlag(vo.getPreliminaryReviewDto().getBusinessLicenseDto().getLicenseCode(), merId)) {
                vo.setReapplyBtnShowFlag(true);
            }
        }

        //证照信息
        getSubmitLicenseInfo(vo, merId);
        //经营信息
        getSubmitBusinessInfo(vo, merId);
        //其他资料
        getSubmitOtherInfo(vo, merId);
        //补件
        getSubmitSupplementaryParts(vo, merId);
        return vo;
    }

    private void getSubmitSupplementaryParts(MerchantInfoVo vo, String merId) {
        //获取补件信息
        List<MerAttachDto> merAttachDtos = merAttachService.selectBuJianAttachList(merId);
        if (!CollectionUtils.isEmpty(merAttachDtos)) {
            vo.setAttachDtoList(merAttachDtos);
        }
    }

    private void getSubmitOtherInfo(MerchantInfoVo vo, String merId) {
        SubmitOtherInfoDto dto = new SubmitOtherInfoDto();
        dto.setMerId(merId);
        //分期信息
        MerInstallmentInfoDto installmentInfoDto = new MerInstallmentInfoDto();

        MerInstallmentInfo one = merInstallmentInfoService.getOne(Wrappers.<MerInstallmentInfo>lambdaQuery().eq(MerInstallmentInfo::getMerId, merId));
        if (Objects.nonNull(one)) {
            BeanUtils.copyPropertiesIgnoreNull(one, installmentInfoDto);
            List<MerInstallmentInfoCompetitiveDto> list = merInstallmentInfoCompetitiveService.listByInstallmentId(one.getInstallmentId());
            if (!CollectionUtils.isEmpty(list)) {
                installmentInfoDto.setCompetitiveList(list);
            }
            dto.setInstallmentInfoDto(installmentInfoDto);
        }

        //收款户信息
        List<MerBackCardDto> backCardDtos = merBankCardService.listByMerId(merId);
        if (!CollectionUtils.isEmpty(backCardDtos)) {
            dto.setBackCardDto(backCardDtos);
        } else {
            //银行账户无数据则将开户信息填充到收款户信息
            List<MerBackCardDto> cardDtoList = merAccountLicenseService.listByMerId(merId);
            //开户信息默认对公
            cardDtoList.forEach(dto1 -> dto1.setCardType(CommonEnum.CardTypeEnum.PUBLIC.getCode()));
            dto.setBackCardDto(cardDtoList);
        }

        //资方顺位
        List<MerMerchantCapitalOrderDto> merchantCapitalOrderDtos = merMerchantCapitalOrderService.listByMerId(merId);
        if (!CollectionUtils.isEmpty(merchantCapitalOrderDtos)) {
            dto.setCapitalOrderDto(merchantCapitalOrderDtos);
        }
        MerMerchant merchant = merMerchantService.getById(merId);
        //费率
        List<MerchantRateDto> merchantRateDtos = merMerchantRateManageService.listByMerId(merId, merchant.getSceneParentCategory());
        if (!CollectionUtils.isEmpty(merchantRateDtos)) {
            dto.setSourceInfoDto(merchantRateDtos);
            vo.setOtherInfoDto(dto);
            return;
        }
        //使用引擎的资方顺位去查询费率
        /**
         * 2025-09-29 第二次优化： 每个资方仅自动带出一行“创建时间”最靠前的费率模板即可，不需要把该资方所有费率模板都自动带出来
         */
        List<MerMerchantRiskCapitalOrder> riskCapitalOrders = merMerchantRiskCapitalOrderService.list(Wrappers.<MerMerchantRiskCapitalOrder>lambdaQuery().eq(MerMerchantRiskCapitalOrder::getMerId, merId));
        List<String> sourceIds = riskCapitalOrders.stream()
                .map(MerMerchantRiskCapitalOrder::getSourceId)
                .collect(Collectors.toList());
        List<MerchantRateDto> rateDtoList = merAssetRateManageService.queryListBySourceId(sourceIds, merchant.getSceneParentCategory());
        merAssetRateManageDetailService.fillInRateDetails(rateDtoList);
        dto.setSourceInfoDto(rateDtoList);
        vo.setOtherInfoDto(dto);
    }

    private void getSubmitBusinessInfo(MerchantInfoVo vo, String merId) {
        SubmitBusinessInfoDto businessInfoVo = new SubmitBusinessInfoDto();
        businessInfoVo.setMerId(merId);
        MerRunInfo merRunInfo = merRunInfoService.getOne(Wrappers.<MerRunInfo>lambdaQuery().eq(MerRunInfo::getMerId, merId));
        if (Objects.nonNull(merRunInfo)) {
            //经营信息
            MerBusinessInfoDto businessInfo = new MerBusinessInfoDto();
            BeanUtils.copyPropertiesIgnoreNull(merRunInfo, businessInfo);
            //如果是本地单店并且不存在门店数量，则设置为1
            if (businessInfo.getStoreNumber() == null && vo.getPreliminaryReviewDto() != null
                    && vo.getPreliminaryReviewDto().getInitialReviewInfoDto() != null && vo.getPreliminaryReviewDto().getInitialReviewInfoDto().getStoreType() != null
                    && vo.getPreliminaryReviewDto().getInitialReviewInfoDto().getStoreType().equals(CommonEnum.storeType.LOCAL_STORE.name())) {
                businessInfo.setStoreNumber(1);
            }
            businessInfoVo.setMerBusinessInfo(businessInfo);
        } else {
            //如果是本地单店并且不存在门店数量，则设置为1
            if (vo.getPreliminaryReviewDto() != null
                    && vo.getPreliminaryReviewDto().getInitialReviewInfoDto() != null && vo.getPreliminaryReviewDto().getInitialReviewInfoDto().getStoreType() != null
                    && vo.getPreliminaryReviewDto().getInitialReviewInfoDto().getStoreType().equals(CommonEnum.storeType.LOCAL_STORE.name())) {
                MerBusinessInfoDto businessInfo = new MerBusinessInfoDto();
                businessInfo.setStoreNumber(1);
                businessInfoVo.setMerBusinessInfo(businessInfo);
            }
        }
        //查询经营附件数据 附件类型(1,初审附件,2,企业征信附件,3,经营附件)
        List<MerAttachDto> list = merAttachService.queryAttachListByOperate(merId, 3);
        if (!CollectionUtils.isEmpty(list)) {
            for (MerAttachDto merAttach : list) {
                List<MerAttachValue> attachValues = merAttachValueService.list(Wrappers.<MerAttachValue>lambdaQuery().eq(MerAttachValue::getAttachId, merAttach.getAttachId()));
                merAttach.setAttachResultList(attachValues.stream().map(MerAttachValue::getValValue).collect(Collectors.toList()));
            }
            businessInfoVo.setMerAttachList(list);
        } else {
            List<MerAttachDto> configList = new ArrayList<>();
            List<String> attachTypeList = Arrays.asList("TY", vo.getSceneParentCategory());
            List<MerAttachConfig> attachConfigList = merAttachConfigService.list(Wrappers.<MerAttachConfig>lambdaQuery()
                    .in(MerAttachConfig::getAttachSceneCategory, attachTypeList)
                    .eq(MerAttachConfig::getAttachType, 3)
                    .orderByAsc(MerAttachConfig::getOrderNo));
            attachConfigList.forEach(config -> {
                MerAttachDto merAttachDto = new MerAttachDto();
                merAttachDto.setMerId(merId);
                merAttachDto.setConfigCode(config.getConfigCode());
                merAttachDto.setConfigName(config.getConfigName());
                merAttachDto.setConfigMin(config.getConfigMin());
                merAttachDto.setConfigMax(config.getConfigMax());
                merAttachDto.setConfigRequire(config.getConfigRequire());
                configList.add(merAttachDto);
            });
            businessInfoVo.setMerAttachList(configList);
        }
        vo.setBusinessInfoDto(businessInfoVo);
    }

    /**
     * 获取证照信息
     *
     * @param vo
     * @param merId
     */
    private void getSubmitLicenseInfo(MerchantInfoVo vo, String merId) {
        SubmitLicenseInfoDto licenseInfoVo = new SubmitLicenseInfoDto();
        licenseInfoVo.setMerId(merId);
        MerMerchant merchant = merMerchantService.getById(merId);
        MerLicense merLicense = merLicenseService.getOne(Wrappers.<MerLicense>lambdaQuery().eq(MerLicense::getMerId, merId));
        if (Objects.equals(merchant.getSceneParentCategory(), CommonEnum.sceneCategory.DJK.name())) {
            // 大健康执行许可
            MerMedicalLicense merMedicalLicense = merMedicalLicenseService.getOne(Wrappers.<MerMedicalLicense>lambdaQuery().eq(MerMedicalLicense::getMerId, merId));
            MedicalLicenseDto medicalLicenseDto = new MedicalLicenseDto();
            if (Objects.nonNull(merMedicalLicense)) {
                BeanUtils.copyPropertiesIgnoreNull(merMedicalLicense, medicalLicenseDto);
                String medlImage = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.practice_license.name());
                medicalLicenseDto.setMedlImage(medlImage);
            } else {
                //从营业信息里面取
                medicalLicenseDto.setMedlName(merLicense.getLicenseName());
                medicalLicenseDto.setMedlLegalMan(merLicense.getLicenseLegalMan());
                medicalLicenseDto.setMedlProvince(merLicense.getLicenseProvince());
                medicalLicenseDto.setMedlCity(merLicense.getLicenseCity());
                medicalLicenseDto.setMedlCountry(merLicense.getLicenseCountry());
                medicalLicenseDto.setMedlAddress(merLicense.getLicenseAddress());
            }
            licenseInfoVo.setMedicalLicenseDto(medicalLicenseDto);
        } else {
            // 教育办学执行许可
            MerMedicalEduLicense educationLicense = merMedicalEduLicenseService.getOne(Wrappers.<MerMedicalEduLicense>lambdaQuery().eq(MerMedicalEduLicense::getMerId, merId));
            MedicalEduLicenseDto medicalEduLicenseDto = new MedicalEduLicenseDto();
            if (Objects.nonNull(educationLicense)) {
                BeanUtils.copyPropertiesIgnoreNull(educationLicense, medicalEduLicenseDto);
                String edulImage = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.education_license.name());
                medicalEduLicenseDto.setFileUrl(edulImage);
            } else {
                //从营业信息里面取
                medicalEduLicenseDto.setInstitutionName(merLicense.getLicenseName());
                medicalEduLicenseDto.setLegalName(merLicense.getLicenseLegalMan());
                medicalEduLicenseDto.setProvince(merLicense.getLicenseProvince());
                medicalEduLicenseDto.setCity(merLicense.getLicenseCity());
                medicalEduLicenseDto.setCountry(merLicense.getLicenseCountry());
                medicalEduLicenseDto.setAddress(merLicense.getLicenseAddress());
            }
            licenseInfoVo.setMerEduLicenseDto(medicalEduLicenseDto);
            // 获取教育ICP许可证
            MerMedicalEduIcpLicense medicalEduIcpLicense = merMedicalEduIcpLicenseService.getOne(Wrappers.<MerMedicalEduIcpLicense>lambdaQuery().eq(MerMedicalEduIcpLicense::getMerId, merId));
            MedicalEduIcpLicenseDto medicalEduIcpLicenseDto = new MedicalEduIcpLicenseDto();
            if (Objects.nonNull(medicalEduIcpLicense)) {
                BeanUtils.copyPropertiesIgnoreNull(medicalEduIcpLicense, medicalEduIcpLicenseDto);
                String icpImage = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.icp_license.name());
                medicalEduIcpLicenseDto.setFileUrl(icpImage);
            } else {
                medicalEduIcpLicenseDto.setCompanyName(merLicense.getLicenseName());
                medicalEduIcpLicenseDto.setLegalName(merLicense.getLicenseLegalMan());
            }
            licenseInfoVo.setMerEduIcpLicenseDto(medicalEduIcpLicenseDto);
        }
        // 产权信息
        MerVenueInfoDto merVenueInfoDto = new MerVenueInfoDto();
        //开户信息
        MerAccountLicenseDto merAccountLicenseDto = new MerAccountLicenseDto();

        MerVenueInfo venueInfo = merVenueInfoService.getOne(Wrappers.<MerVenueInfo>lambdaQuery().eq(MerVenueInfo::getMerId, merId));
        if (Objects.nonNull(venueInfo)) {
            BeanUtils.copyPropertiesIgnoreNull(venueInfo, merVenueInfoDto);
            List<String> venueImage = merAttachService.selectByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.lease_agreement.name());
            merVenueInfoDto.setVenueContract(venueImage);
            if (venueInfo.getRentalArea() == null) {
                merVenueInfoDto.setRentalArea(merVenueInfoDto.getVenueArea());
            }
            //去营业执照数据
            if (!StringUtils.hasText(merVenueInfoDto.getVenueProvince())) {
                merVenueInfoDto.setVenueProvince(merLicense.getLicenseProvince());
                merVenueInfoDto.setRealProvince(merLicense.getLicenseProvince());
            }
            if (!StringUtils.hasText(merVenueInfoDto.getVenueCity())) {
                merVenueInfoDto.setVenueCity(merLicense.getLicenseCity());
                merVenueInfoDto.setRealCity(merLicense.getLicenseCity());
            }
            if (!StringUtils.hasText(merVenueInfoDto.getVenueCountry())) {
                merVenueInfoDto.setVenueCountry(merLicense.getLicenseCountry());
                merVenueInfoDto.setRealCountry(merLicense.getLicenseCountry());
            }
            if (!StringUtils.hasText(merVenueInfoDto.getVenueAddress())) {
                merVenueInfoDto.setVenueAddress(merLicense.getLicenseAddress());
                merVenueInfoDto.setRealAddress(merLicense.getLicenseAddress());
            }
        }
        licenseInfoVo.setVenueInfoDto(merVenueInfoDto);

        MerAccountLicense accountLicense = merAccountLicenseService.getOne(Wrappers.<MerAccountLicense>lambdaQuery().eq(MerAccountLicense::getMerId, merId));
        if (Objects.nonNull(accountLicense)) {
            BeanUtils.copyPropertiesIgnoreNull(accountLicense, merAccountLicenseDto);
            String acclImage = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.account_opening_license.name());
            merAccountLicenseDto.setAcclImage(acclImage);
        }

        licenseInfoVo.setAccountLicenseDto(merAccountLicenseDto);

        vo.setLicenseInfoDto(licenseInfoVo);
    }

    /**
     * 获取初审信息
     *
     * @param vo
     * @param merId
     */
    private void getSubmitPreliminaryReview(MerchantInfoVo vo, String merId) {
        SubmitPreliminaryReviewDto preliminaryReviewDto = new SubmitPreliminaryReviewDto();
        preliminaryReviewDto.setMerId(merId);
        //场景信息
        SceneInfoVoDto sceneInfoDto = new SceneInfoVoDto();
        //营业执照
        BusinessLicenseDto businessLicenseDto = new BusinessLicenseDto();
        //法人信息
        CorporateInfoDto corporateInfoDto = new CorporateInfoDto();
        MerMerchant merchant = merMerchantService.getById(merId);
        if (Objects.nonNull(merchant)) {
            BeanUtils.copyPropertiesIgnoreNull(merchant, sceneInfoDto);
            //初审信息
            InitialReviewInfoDto initialReviewInfoDto = new InitialReviewInfoDto();
            BeanUtils.copyPropertiesIgnoreNull(merchant, initialReviewInfoDto);
            MerVenueInfo venueInfo = merVenueInfoService.getOne(Wrappers.<MerVenueInfo>lambdaQuery().eq(MerVenueInfo::getMerId, merId));
            if (Objects.nonNull(venueInfo)) {
                initialReviewInfoDto.setVenueArea(venueInfo.getVenueArea());
                preliminaryReviewDto.setInitialReviewInfoDto(initialReviewInfoDto);
            }
            //商户简称
            businessLicenseDto.setLicenseShortName(merchant.getMerShortName());
        }
        preliminaryReviewDto.setSceneInfoDto(sceneInfoDto);

        MerLicense merLicense = merLicenseService.getOne(Wrappers.<MerLicense>lambdaQuery().eq(MerLicense::getMerId, merId));
        if (Objects.nonNull(merLicense)) {
            BeanUtils.copyPropertiesIgnoreNull(merLicense, businessLicenseDto);
            //获取附件
            String url = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.business_license.name());
            businessLicenseDto.setLicenseImage(url);
        }

        preliminaryReviewDto.setBusinessLicenseDto(businessLicenseDto);

        MerLegalInfo merLegalInfo = merLegalInfoService.getOne(Wrappers.<MerLegalInfo>lambdaQuery().eq(MerLegalInfo::getMerId, merId));
        if (Objects.nonNull(merLegalInfo)) {
            BeanUtils.copyPropertiesIgnoreNull(merLegalInfo, corporateInfoDto);
            //获取法人身份证正面地址
            String legalIdCardFrontUrl = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.legal_id_card_front.name());
            //法人身份证反面
            String legalIdCardBackUrl = merAttachService.selectAttachByMerIdAndConfigCode(merId, CommonEnum.businessPhotoType.legal_id_card_back.name());
            corporateInfoDto.setLegalIdCardFront(legalIdCardFrontUrl);
            corporateInfoDto.setLegalIdCardBack(legalIdCardBackUrl);
        }
        preliminaryReviewDto.setCorporateInfoDto(corporateInfoDto);
        vo.setPreliminaryReviewDto(preliminaryReviewDto);
    }

    @Override
    public List<Map<String, String>> getExistingMerchants(String merId) {
        return collaborationApplyMapper.getExistingMerchants(merId);
    }

    @Override
    public void submitLicenseInfo(SubmitLicenseInfoDto dto) {
        //保存信息 增加模块类型
        if (!StringUtils.hasText(dto.getSubmitType())) {
            throw BusinessException.businessParamsNotExist("提交类型不能为空");
        }
        //分模块提交
        if (CommonEnum.typeOfCooperationApplicationModule.SAVE.name().equals(dto.getSubmitType()) && StringUtils.hasText(dto.getSubmitModule())) {
            CommonEnum.CooperationApplicationModule module = CommonEnum.CooperationApplicationModule.fromCode(dto.getSubmitModule());
            switch (module) {
                case PRACTICE_LICENSE:
                    this.saveMedicalLicense(dto.getMedicalLicenseDto());
                    break;
                case SCHOOL_LICENSE:
                    this.saveMedicalEduLicense(dto.getMerEduLicenseDto());
                    break;
                case ICP_LICENSE:
                    this.saveMedicalEduIcpLicense(dto.getMerEduIcpLicenseDto());
                    break;
                case PROPERTY_RIGHT:
                    this.saveVenueInfo(dto.getVenueInfoDto());
                    break;
                case OPEN_AN_ACCOUNT:
                    this.saveAccountLicense(dto.getAccountLicenseDto());
                    break;
            }
        }
        //保存
        if (CommonEnum.typeOfCooperationApplicationModule.SAVE.name().equals(dto.getSubmitType()) && !StringUtils.hasText(dto.getSubmitModule())) {
            this.saveMedicalLicense(dto.getMedicalLicenseDto());
            this.saveMedicalEduLicense(dto.getMerEduLicenseDto());
            this.saveMedicalEduIcpLicense(dto.getMerEduIcpLicenseDto());
            this.saveVenueInfo(dto.getVenueInfoDto());
            this.saveAccountLicense(dto.getAccountLicenseDto());
        }
        //下一步
        if (CommonEnum.typeOfCooperationApplicationModule.NEXT_STEP.name().equals(dto.getSubmitType())) {
            this.saveMedicalLicense(dto.getMedicalLicenseDto());
            this.saveMedicalEduLicense(dto.getMerEduLicenseDto());
            this.saveMedicalEduIcpLicense(dto.getMerEduIcpLicenseDto());
            this.saveVenueInfo(dto.getVenueInfoDto());
            this.saveAccountLicense(dto.getAccountLicenseDto());
            //保存并将当前步骤设置为完成
            MerMerchantRegisterStep currentStep = merMerchantRegisterStepService.getOne(Wrappers.<MerMerchantRegisterStep>lambdaQuery()
                    .eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                    .eq(MerMerchantRegisterStep::getStepType, CommonEnum.cooperationApplyStepType.LICENSE_INFORMATION.name()));
            if (currentStep != null && !currentStep.getCompleteFlag()) {
                currentStep.setCompleteFlag(true);
                currentStep.setCurrentFlag(false);
                merMerchantRegisterStepService.updateById(currentStep);
                //将其他步骤设置为非当前步骤
                merMerchantRegisterStepService.update(Wrappers.<MerMerchantRegisterStep>lambdaUpdate().eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                        .set(MerMerchantRegisterStep::getCurrentFlag, false));
                //将下一步设置为当前步骤
                MerMerchantRegisterStep nextStep = merMerchantRegisterStepService.getOne(Wrappers.<MerMerchantRegisterStep>lambdaQuery()
                        .eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                        .eq(MerMerchantRegisterStep::getStepType, CommonEnum.cooperationApplyStepType.BUSINESS_INFORMATION.name()));
                if (nextStep != null) {
                    nextStep.setCurrentFlag(true);
                    merMerchantRegisterStepService.updateById(nextStep);
                }
                //生成商户附件类型
                createMerAttach(dto.getMerId());
            }
        }
    }

    /**
     * 创建商户附件
     *
     * @param merId 商户ID
     */
    private void createMerAttach(String merId) {
        //如果已经存在则跳过
        List<MerAttach> list = merAttachService.list(Wrappers.<MerAttach>lambdaQuery()
                .eq(MerAttach::getMerId, merId)
                .eq(MerAttach::getAttachType, 3));
        if (!CollectionUtils.isEmpty(list)) {
            log.info("商户附件已经存在，无需创建");
            return;
        }
        MerMerchant merchant = merMerchantService.getById(merId);
        List<String> attachTypeList = Arrays.asList("TY", merchant.getSceneParentCategory());
        List<MerAttachConfig> attachConfigList = merAttachConfigService.list(Wrappers.<MerAttachConfig>lambdaQuery()
                .in(MerAttachConfig::getAttachSceneCategory, attachTypeList)
                .eq(MerAttachConfig::getAttachType, 3)
                .orderByAsc(MerAttachConfig::getOrderNo));
        attachConfigList.forEach(dto -> {
            MerAttach merAttach = new MerAttach();
            //默认为经营附件
            merAttach.setAttachType(3);
            merAttach.setMerId(merId);
            merAttach.setConfigName(dto.getConfigName());
            merAttach.setConfigCode(dto.getConfigCode());
            merAttachService.save(merAttach);
        });
    }

    private void saveMedicalEduIcpLicense(MedicalEduIcpLicenseDto dto) {
        if (Objects.isNull(dto)) {
            return;
        }
        if (StringUtils.hasText(dto.getValidateStart())) {
            LocalDate startTime = LocalDate.parse(dto.getValidateStart());
            LocalDate now = LocalDate.now();
            if (startTime.isAfter(now)) {
                throw BusinessException.businessValidateError("ICP有效期开始日期不能大于今天");
            }
        }
        if (StringUtils.hasText(dto.getValidateEnd()) && !Objects.equals("长期", dto.getValidateEnd())) {
            LocalDate endTime = LocalDate.parse(dto.getValidateEnd());
            LocalDate now = LocalDate.now();
            if (endTime.isBefore(now)) {
                throw BusinessException.businessValidateError("ICP有效期结束日期不能小于今天");
            }
        }
        if (!StringUtils.hasText(dto.getFileUrl())) {
            log.warn("未传ICP许可证，则不保存或更新信息");
            return;
        }
        MerMedicalEduIcpLicense license = merMedicalEduIcpLicenseService.getOne(Wrappers.<MerMedicalEduIcpLicense>lambdaQuery().eq(MerMedicalEduIcpLicense::getMerId, dto.getMerId()));
        if (license == null) {
            license = new MerMedicalEduIcpLicense();
        }

        BeanUtils.copyPropertiesIgnoreNull(dto, license);
        merMedicalEduIcpLicenseService.saveOrUpdate(license);
        //更新附件
        merAttachService.edit(dto.getMerId(), dto.getFileUrl(), CommonEnum.businessPhotoType.icp_license, 1);
    }

    private void saveMedicalEduLicense(MedicalEduLicenseDto dto) {
        if (Objects.isNull(dto)) {
            return;
        }
        if (StringUtils.hasText(dto.getValidateStart())) {
            LocalDate startTime = LocalDate.parse(dto.getValidateStart());
            LocalDate now = LocalDate.now();
            if (startTime.isAfter(now)) {
                throw BusinessException.businessValidateError("办学许可证执业有效期开始日期不能大于今天");
            }
        }
        if (StringUtils.hasText(dto.getValidateEnd()) && !Objects.equals("长期", dto.getValidateEnd())) {
            LocalDate endTime = LocalDate.parse(dto.getValidateEnd());
            LocalDate now = LocalDate.now();
            if (endTime.isBefore(now)) {
                throw BusinessException.businessValidateError("办学许可证执业有效期结束日期不能小于今天");
            }
        }
        if (!StringUtils.hasText(dto.getFileUrl())) {
            log.warn("未传办学许可证，则不保存或更新信息");
            return;
        }
        MerMedicalEduLicense license = merMedicalEduLicenseService.getOne(Wrappers.<MerMedicalEduLicense>lambdaQuery().eq(MerMedicalEduLicense::getMerId, dto.getMerId()));
        if (license == null) {
            license = new MerMedicalEduLicense();
        }
        BeanUtils.copyPropertiesIgnoreNull(dto, license);
        merMedicalEduLicenseService.saveOrUpdate(license);
        //更新附件
        merAttachService.edit(dto.getMerId(), dto.getFileUrl(), CommonEnum.businessPhotoType.education_license, 1);
    }


    @Override
    public void submitBusinessInfo(SubmitBusinessInfoDto dto) {
        if (!StringUtils.hasText(dto.getSubmitType())) {
            throw BusinessException.businessParamsNotExist("提交类型不能为空");
        }
        if (CommonEnum.typeOfCooperationApplicationModule.SAVE.name().equals(dto.getSubmitType()) && StringUtils.hasText(dto.getSubmitModule())) {
            CommonEnum.SubmitBusinessInfoModel model = CommonEnum.SubmitBusinessInfoModel.fromCode(dto.getSubmitModule());
            switch (model) {
                case BUSINESS_INFO:
                    //营业信息
                    this.saveMerBusinessInfo(dto.getMerBusinessInfo(), dto.getMerId());
                    break;
                case BUSINESS_FILE:
                    //营业附件信息
                    this.saveMerBusinessFile(dto.getMerAttachList(), dto.getMerId());
                    break;
                default:
                    throw BusinessException.businessParamsNotExist("模块类型不存在");
            }
        }
        if (CommonEnum.typeOfCooperationApplicationModule.SAVE.name().equals(dto.getSubmitType()) && !StringUtils.hasText(dto.getSubmitModule())) {
            //保存
            this.saveMerBusinessInfo(dto.getMerBusinessInfo(), dto.getMerId());
            this.saveMerBusinessFile(dto.getMerAttachList(), dto.getMerId());
        }
        if (CommonEnum.typeOfCooperationApplicationModule.NEXT_STEP.name().equals(dto.getSubmitType())) {
            //保存并更新步骤信息
            this.saveMerBusinessInfo(dto.getMerBusinessInfo(), dto.getMerId());
            this.saveMerBusinessFile(dto.getMerAttachList(), dto.getMerId());
            //保存并将当前步骤设置为完成
            MerMerchantRegisterStep currentStep = merMerchantRegisterStepService.getOne(Wrappers.<MerMerchantRegisterStep>lambdaQuery()
                    .eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                    .eq(MerMerchantRegisterStep::getStepType, CommonEnum.cooperationApplyStepType.BUSINESS_INFORMATION.name()));
            if (currentStep != null && !currentStep.getCompleteFlag()) {
                currentStep.setCompleteFlag(true);
                currentStep.setCurrentFlag(false);
                merMerchantRegisterStepService.updateById(currentStep);
                //将其他步骤设置为非当前步骤
                merMerchantRegisterStepService.update(Wrappers.<MerMerchantRegisterStep>lambdaUpdate().eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                        .set(MerMerchantRegisterStep::getCurrentFlag, false));
                //将下一步设置为当前步骤
                MerMerchantRegisterStep nextStep = merMerchantRegisterStepService.getOne(Wrappers.<MerMerchantRegisterStep>lambdaQuery()
                        .eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                        .eq(MerMerchantRegisterStep::getStepType, CommonEnum.cooperationApplyStepType.OTHERS.name()));
                if (nextStep != null) {
                    nextStep.setCurrentFlag(true);
                    merMerchantRegisterStepService.updateById(nextStep);
                }
                //调用引擎获取支持资方
                riskEgService.submitRiskEg(dto.getMerId(), CommonEnum.riskControlEngineType.OBTAIN_FUNDING);
            }
        }
    }

    @Override
    public SubmitOtherInfoDto submitOtherInfo(SubmitOtherInfoDto dto) {
        if (!StringUtils.hasText(dto.getSubmitType())) {
            throw BusinessException.businessParamsNotExist("提交类型不能为空");
        }
        if (CommonEnum.typeOfCooperationApplicationModule.SAVE.name().equals(dto.getSubmitType()) && StringUtils.hasText(dto.getSubmitModule())) {
            CommonEnum.OtherDataModel otherDataModel = CommonEnum.OtherDataModel.fromCode(dto.getSubmitModule());
            switch (otherDataModel) {
                case INSTALLMENT_INFO:
                    //分期信息
                    this.saveInstallmentInfo(dto.getInstallmentInfoDto(), dto.getMerId());
                    break;
                case RECIPIENT_INFO:
                    //收款户信息
                    this.saveBackCard(dto.getBackCardDto(), dto.getMerId());
                    break;
                case INVESTOR_INFO:
                    //资方顺位
                    this.saveCapitalOrder(dto.getCapitalOrderDto(), dto.getMerId());
                    break;
                case RATE_INFO:
                    //费率信息
                    this.saveRateInfo(dto.getSourceInfoDto(), dto.getMerId());
                    break;
                default:
                    throw BusinessException.businessParamsNotExist("模块类型不存在");
            }
        }
        if (CommonEnum.typeOfCooperationApplicationModule.SAVE.name().equals(dto.getSubmitType()) && !StringUtils.hasText(dto.getSubmitModule())) {
            //分期信息
            this.saveInstallmentInfo(dto.getInstallmentInfoDto(), dto.getMerId());
            //收款户信息
            this.saveBackCard(dto.getBackCardDto(), dto.getMerId());
            //保存资方顺位
            this.saveCapitalOrder(dto.getCapitalOrderDto(), dto.getMerId());
            //保存费率
            this.saveRateInfo(dto.getSourceInfoDto(), dto.getMerId());
        }
        if (CommonEnum.typeOfCooperationApplicationModule.SUBMIT_FOR_REVIEW.name().equals(dto.getSubmitType())) {
            //分期信息
            this.saveInstallmentInfo(dto.getInstallmentInfoDto(), dto.getMerId());
            //收款户信息
            this.saveBackCard(dto.getBackCardDto(), dto.getMerId());
            //保存资方顺位
            this.saveCapitalOrder(dto.getCapitalOrderDto(), dto.getMerId());
            //保存费率
            this.saveRateInfo(dto.getSourceInfoDto(), dto.getMerId());
            //保存并将当前步骤设置为完成
            MerMerchantRegisterStep currentStep = merMerchantRegisterStepService.getOne(Wrappers.<MerMerchantRegisterStep>lambdaQuery()
                    .eq(MerMerchantRegisterStep::getMerId, dto.getMerId())
                    .eq(MerMerchantRegisterStep::getStepType, CommonEnum.cooperationApplyStepType.OTHERS.name()));
            if (currentStep != null) {
                currentStep.setCompleteFlag(true);
                //只有第一步和第四步才设置提交时间
                currentStep.setSubmitTime(LocalDateTime.now());
                merMerchantRegisterStepService.updateById(currentStep);
            }
            //设置审核状态
            this.updateMerchantAuditStatus(MerchantAuditStatusDto.builder()
                    .merId(dto.getMerId())
                    .auditStatus(CommonEnum.auditType.PENDING_APPROVAL.name())
                    .auditType(CommonEnum.merchantAuditType.COLLABORATION_REVIEW.name())
                    .reexamineFlag(true)
                    .submitPreliminaryReviewFlag(false)
                    .build());
        }
        MerchantInfoVo merchantInfo = new MerchantInfoVo();
        getSubmitOtherInfo(merchantInfo, dto.getMerId());
        return merchantInfo.getOtherInfoDto();
    }

    @Override
    public void withdraw(String merId) {
        if (!StringUtils.hasText(merId)) {
            throw BusinessException.businessParamsNotExist("商户ID不能为空");
        }
        MerMerchant merMerchant = merMerchantService.getById(merId);
        if (Objects.isNull(merMerchant)) {
            throw BusinessException.businessParamsNotExist("商户不存在");
        }
        LocalDateTime now = LocalDateTime.now();
        merMerchantService.updateById(merMerchant);
        MerAuthFlow merAuthFlow = merAuthFlowService.getOne(Wrappers.<MerAuthFlow>lambdaQuery().eq(MerAuthFlow::getMerId, merId));
        if (Objects.isNull(merAuthFlow)) {
            merAuthFlow = new MerAuthFlow();
            merAuthFlow.setMerId(merId);
            merAuthFlow.setAuthStatus(CommonEnum.auditType.WITHDRAW.name());
            merAuthFlow.setAuditType(CommonEnum.merchantAuditType.COLLABORATION_REVIEW.name());
            merAuthFlow.setCancelTime(now);
            merAuthFlowService.save(merAuthFlow);
            MerAuthFlowLog merAuthFlowLog = new MerAuthFlowLog();
            merAuthFlowLog.setFlowId(merAuthFlow.getFlowId());
            merAuthFlowLog.setAuthStatus(CommonEnum.auditType.WITHDRAW.name());
            merAuthFlowLog.setAuthManId(SecurityUtils.getUserId());
            merAuthFlowLog.setAuthMan(SecurityUtils.getUsername());
            merAuthFlowLog.setAuthDate(now);
            merAuthFlowLogService.save(merAuthFlowLog);
            return;
        }
        MerAuthFlowLog merAuthFlowLog = getMerAuthFlowLog(merAuthFlow, now);
        merAuthFlowLogService.save(merAuthFlowLog);
        merAuthFlow.setAuthStatus(CommonEnum.auditType.WITHDRAW.name());
        merAuthFlow.setCancelTime(now);
        merAuthFlowService.updateById(merAuthFlow);

    }

    private static MerAuthFlowLog getMerAuthFlowLog(MerAuthFlow merAuthFlow, LocalDateTime now) {
        String lastAuthStatus = merAuthFlow.getAuthStatus();
        MerAuthFlowLog merAuthFlowLog = new MerAuthFlowLog();
        merAuthFlowLog.setFlowId(merAuthFlow.getFlowId());
        merAuthFlowLog.setAuthStatus(CommonEnum.auditType.WITHDRAW.name());
        merAuthFlowLog.setLastAuthStatus(lastAuthStatus);
        merAuthFlowLog.setAuthManId(SecurityUtils.getUserId());
        merAuthFlowLog.setAuthMan(SecurityUtils.getUsername());
        merAuthFlowLog.setAuthDate(now);
        return merAuthFlowLog;
    }

    @Override
    public Page<CollaborationApplyVo> page(CollaborationApplyDto dto) {
        Page<CollaborationApplyVo> page = collaborationApplyMapper.pageSearch(dto.page(), dto);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return page;
        }
        List<CollaborationApplyVo> records = page.getRecords();
        //场景分类转码
        MerParamsDetailVO sceneCategory = merParamsService.cacheDetail("scene_category");
        if (Objects.isNull(sceneCategory) || sceneCategory.getParamsDetailList().isEmpty()) {
            return page;
        }
        //处理场景分类
        for (CollaborationApplyVo vo : records) {
            if (StringUtils.hasText(vo.getSceneCategory())) {
                String paramNameByPrefix = merParamsService.findParamNameByPrefix(vo.getSceneCategory(), sceneCategory.getParamsDetailList());
                vo.setSceneCategory(paramNameByPrefix);
            }
        }
        return page;
    }

    @Override
    public CollaborationApplyStatisticsVo statistics(CollaborationApplyDto dto) {
        return collaborationApplyMapper.statistics(dto);
    }


    @Override
    @Transactional
    public void submitSupplementaryDocuments(List<MerAttachDto> dto) {
        if (CollectionUtils.isEmpty(dto)) {
            throw BusinessException.businessDataNotExist("请选择要上传的附件");
        }
        String merId = dto.get(0).getMerId();
        String lockKey = "supplement_submit:" + merId;
        // 防重复提交，5秒内同一商户不可重复提交
        Object lock = redisService.getCacheObject(lockKey);
        if (lock != null) {
            throw BusinessException.businessDataNotExist("请勿重复提交");
        }
        redisService.setCacheObject(lockKey, "1", 5L, TimeUnit.SECONDS); // 60秒自动过期
        // 翻转案件流程,补件完重新翻转成待审核，等待催员认领
        MerAuthFlow merAuthFlow = merAuthFlowService.getOne(Wrappers.<MerAuthFlow>lambdaQuery().eq(MerAuthFlow::getMerId, merId));
        String lastStatue = merAuthFlow.getAuthStatus();
        merAuthFlow.setAuthStatus(CommonEnum.auditType.PENDING_APPROVAL.name());
        merAuthFlow.setSupplementTime(LocalDateTime.now());
        merAuthFlow.setCurrentAuthMan(null);
        merAuthFlow.setCurrentAuthManId(null);
        merAuthFlow.setSupplementNum(merAuthFlow.getSupplementNum() + 1);
        merAuthFlowService.updateById(merAuthFlow);
        //记录审核日志
        saveAuthLog(merAuthFlow, lastStatue);
        for (MerAttachDto attachDto : dto) {
            // 查询历史的附件
            List<String> attachResultList = attachDto.getAttachResultList();
            if (CollectionUtils.isEmpty(attachResultList)) {
                throw BusinessException.businessDataNotExist("请选择要上传的附件");
            }
            try {
                // 保存主附件记录
                MerAttach merAttach = new MerAttach();
                merAttach.setMerId(attachDto.getMerId());
                merAttach.setConfigCode(attachDto.getConfigCode());
                merAttach.setConfigName(attachDto.getConfigName());
                merAttach.setEventData(attachDto.getEventData());
                merAttach.setRiskLevel(attachDto.getRiskLevel());
                merAttach.setEventDetail(attachDto.getEventDetail());
                merAttach.setOpinion(attachDto.getOpinion());
                merAttach.setAttachType(attachDto.getAttachType());
                merAttach.setAttachResult("补件");
                merAttach.setSupplementCount(merAuthFlow.getSupplementNum());

                merAttachService.save(merAttach);
                // 批量保存附件详情
                List<MerAttachValue> values = attachResultList.stream()
                        .map(value -> {
                            MerAttachValue attachValue = new MerAttachValue();
                            attachValue.setAttachId(merAttach.getAttachId());
                            attachValue.setValValue(value);
                            return attachValue;
                        })
                        .collect(Collectors.toList());
                merAttachValueService.saveBatch(values);
            } catch (Exception e) {
                log.error("保存附件及详情失败", e);
                throw BusinessException.businessOther("保存附件及详情失败");
            }
        }
        //将合作申请的补件流程翻转成已完成状态
        MerMerchantRegisterStep supplementaryPartsStep = merMerchantRegisterStepService.getOne(
                Wrappers.<MerMerchantRegisterStep>lambdaQuery()
                        .eq(MerMerchantRegisterStep::getMerId, merId)
                        .eq(MerMerchantRegisterStep::getCurrentFlag, true));
        supplementaryPartsStep.setCompleteFlag(true);
        merMerchantRegisterStepService.updateById(supplementaryPartsStep);
        // 更新当前商户的补件时间为当前时间

    }

    private void saveAuthLog(MerAuthFlow merAuthFlow, String lastStatue) {
        MerAuthFlowLog merAuthFlowLog = new MerAuthFlowLog();
        merAuthFlowLog.setFlowId(merAuthFlow.getFlowId());
        merAuthFlowLog.setAuthStatus(merAuthFlow.getAuthStatus());
        merAuthFlowLog.setLastAuthStatus(lastStatue);
        merAuthFlowLog.setAuthRemark(CommonEnum.auditType.PENDING_APPROVAL.getDescription());
        merAuthFlowLog.setAuthManId(SecurityUtils.getUserId());
        merAuthFlowLog.setAuthMan(SecurityUtils.getUsername());
        merAuthFlowLog.setAuthDate(LocalDateTime.now());
        merAuthFlowLogService.save(merAuthFlowLog);
    }

    @Override
    public List<MerchantRateDto> getMerchantRateIRR(String merId, String sceneCategory) {
        return merMerchantRateManageService.listByMerIdIRR(merId, sceneCategory);
    }

    @Override
    public String reapply(String merId) {
        //1、参数校验
        if (!StringUtils.hasText(merId)) {
            throw BusinessException.businessParamsNotExist("商户ID不能为空");
        }
        MerMerchant merchant = merMerchantService.getById(merId);
        if (merchant == null) {
            throw BusinessException.businessDataNotExist("商户不存在");
        }
        //是否已重新申请过
        if (StringUtils.hasText(merchant.getReapplyRelatedMerId())) {
            throw BusinessException.businessDataNotExist("商户已重新申请过，请勿重复申请");
        }
        MerAuthFlow merAuthFlow = merAuthFlowService.getOne(Wrappers.<MerAuthFlow>lambdaQuery().eq(MerAuthFlow::getMerId, merId));
        if (merAuthFlow == null) {
            throw BusinessException.businessDataNotExist("商户审核流程不存在");
        }
        //2、商户状态校验 初审退回或复审退回
        List<String> authStatus = Arrays.asList(CommonEnum.auditType.INITIAL_REVIEW_RETURNED.name(),
                CommonEnum.auditType.REVIEW_RETURNED.name(),
                CommonEnum.auditType.INITIAL_REVIEW_REFUSED.name(),
                CommonEnum.auditType.REVIEW_REFUSED.name(),
                CommonEnum.auditType.WITHDRAW.name());
        if (!authStatus.contains(merAuthFlow.getAuthStatus())) {
            throw BusinessException.businessDataNotExist("当前商户非初审退回/复审退回/初审拒绝/复审拒绝/取消申请,无法重新申请");
        }
        //3、校验时间
        //默认30天
        int limitTheNumberOfDays = 30;
        // 初审退回或者复审退回的数据，30天之内可以发起重新提交，30天之后就只能点商户入驻去重新录入资料提交了
        List<MerParamsDetailDTO> examineRefuse = merParamsService.getParams("examine_return", null);
        if (CollectionUtils.isNotEmpty(examineRefuse)) {
            limitTheNumberOfDays = Integer.parseInt(examineRefuse.get(0).getParamKey());
        }
        boolean flag = merMerchantService.checkReturnTime(merId, limitTheNumberOfDays, merAuthFlow.getAuthStatus());
        if (flag) {
            throw BusinessException.businessDataNotExist("初审退回/复审退回已超30天，请重新进行商户入驻");
        }
        //4、根据商户状态重新生成商户信息并更新老商户关联商户id
        if (Arrays.asList(CommonEnum.auditType.INITIAL_REVIEW_RETURNED.name(),
                CommonEnum.auditType.INITIAL_REVIEW_REFUSED.name()).contains(merAuthFlow.getAuthStatus())) {
            //初审退回、初审拒绝
            return this.handlingInitialReviewReturns(merchant);
        }
        if (Arrays.asList(CommonEnum.auditType.REVIEW_RETURNED.name(),
                CommonEnum.auditType.REVIEW_REFUSED.name(),
                CommonEnum.auditType.WITHDRAW.name()).contains(merAuthFlow.getAuthStatus())) {
            //复审退回、复审拒绝
            return this.handlingReviewReturned(merchant);
        }
        throw BusinessException.businessParamsNotExist("商户状态错误");
    }

    @Override
    public void checkMerShortName(String merShortName, String merId) {
        //1、校验申请中是否存在商户简称
        merLicenseService.checkLicenseCode(null, null, merShortName, true, merId);
        //2、校验拒绝的是否存在商户简称
        merLicenseService.checkMerchant(null, null, merShortName, true, merId);
    }

    private String handlingReviewReturned(MerMerchant merchant) {
        //1、复制保存商户信息
        MerMerchant newMerchant = copyAndSaveMerchant(merchant.getMerId(), merchant, Arrays.asList(1, 3));
        //2、新增许可证
        if (merchant.getSceneParentCategory().equals(CommonEnum.sceneCategory.DJK.name())) {
            MerMedicalLicense merMedicalLicense = merMedicalLicenseService.getOne(Wrappers.<MerMedicalLicense>lambdaQuery().eq(MerMedicalLicense::getMerId, merchant.getMerId()));
            if (merMedicalLicense != null) {
                merMedicalLicense.setMedlId(null);
                merMedicalLicense.setMerId(newMerchant.getMerId());
                merMedicalLicenseService.save(merMedicalLicense);
            }
        } else {
            //教育
            MerMedicalEduLicense license = merMedicalEduLicenseService.getOne(Wrappers.<MerMedicalEduLicense>lambdaQuery().eq(MerMedicalEduLicense::getMerId, merchant.getMerId()));
            if (license != null) {
                license.setMmelId(null);
                license.setMerId(newMerchant.getMerId());
                merMedicalEduLicenseService.save(license);
            }
            MerMedicalEduIcpLicense icpLicense = merMedicalEduIcpLicenseService.getOne(Wrappers.<MerMedicalEduIcpLicense>lambdaQuery().eq(MerMedicalEduIcpLicense::getMerId, merchant.getMerId()));
            if (icpLicense != null) {
                icpLicense.setMeilId(null);
                icpLicense.setMerId(newMerchant.getMerId());
                merMedicalEduIcpLicenseService.save(icpLicense);
            }
        }

        //3、开户许可证
        MerAccountLicense accountLicense = merAccountLicenseService.getOne(Wrappers.<MerAccountLicense>lambdaQuery().eq(MerAccountLicense::getMerId, merchant.getMerId()));
        if (accountLicense != null) {
            accountLicense.setAcclId(null);
            accountLicense.setMerId(newMerchant.getMerId());
            merAccountLicenseService.save(accountLicense);
        }

        //4、经营信息
        MerRunInfo merRunInfo = merRunInfoService.getOne(Wrappers.<MerRunInfo>lambdaQuery().eq(MerRunInfo::getMerId, merchant.getMerId()));
        if (merRunInfo != null) {
            merRunInfo.setRunId(null);
            merRunInfo.setMerId(newMerchant.getMerId());
            merRunInfoService.save(merRunInfo);
        }
        //5、分期信息
        MerInstallmentInfo merInstallmentInfo = merInstallmentInfoService.getOne(Wrappers.<MerInstallmentInfo>lambdaQuery().eq(MerInstallmentInfo::getMerId, merchant.getMerId()));
        if (merInstallmentInfo != null) {
            merInstallmentInfo.setInstallmentId(null);
            merInstallmentInfo.setMerId(newMerchant.getMerId());
            merInstallmentInfoService.save(merInstallmentInfo);
            //竞品明细
            List<MerInstallmentInfoCompetitive> competitiveList = merInstallmentInfoCompetitiveService.list(Wrappers.<MerInstallmentInfoCompetitive>lambdaQuery()
                    .eq(MerInstallmentInfoCompetitive::getInstallmentId, merInstallmentInfo.getInstallmentId()));
            if (CollectionUtils.isEmpty(competitiveList)) {
                return newMerchant.getMerId();
            }
            competitiveList.forEach(item -> {
                MerInstallmentInfoCompetitive competitive = MerInstallmentInfoCompetitive.builder()
                        .installmentId(merInstallmentInfo.getInstallmentId())
                        .competitiveOrganizations(item.getCompetitiveOrganizations())
                        .competitiveRate(item.getCompetitiveRate())
                        .build();
                merInstallmentInfoCompetitiveService.save(competitive);
            });
        }
        return newMerchant.getMerId();
    }

    private String handlingInitialReviewReturns(MerMerchant merchant) {
        //1、复制保存商户信息
        MerMerchant newMerchant = copyAndSaveMerchant(merchant.getMerId(), merchant, Collections.singletonList(1));
        return newMerchant.getMerId();
    }

    /**
     * 复制保存商户信息
     *
     * @param merId    原商户id
     * @param merchant 原商户数据
     * @return
     */
    private MerMerchant copyAndSaveMerchant(String merId, MerMerchant merchant, List<Integer> attachTypeList) {
        //1、新增商户信息
        MerMerchant newMerchant = new MerMerchant();
        BeanUtils.copyPropertiesIgnoreNull(merchant, newMerchant);
        newMerchant.setMerId(null);
        newMerchant.setCreateDate(LocalDateTime.now());
        merMerchantService.save(newMerchant);
        //2、生成步骤
        List<MerMerchantRegisterStep> list = merMerchantRegisterStepService.list(Wrappers.<MerMerchantRegisterStep>lambdaQuery().eq(MerMerchantRegisterStep::getMerId, merId));
        list.forEach(step -> {
            step.setId(null);
            step.setMerId(newMerchant.getMerId());
            step.setCompleteFlag(false);
            step.setCurrentFlag(false);
            if (CommonEnum.cooperationApplyStepType.SUBMIT_PRELIMINARY_REVIEW.name().equals(step.getStepType())) {
                step.setSubmitTime(LocalDateTime.now());
                step.setCurrentFlag(true);
            }
            merMerchantRegisterStepService.save(step);
        });
        //3、新增商户营业执照
        MerLicense merLicense = merLicenseService.getOne(Wrappers.<MerLicense>lambdaQuery().eq(MerLicense::getMerId, merId));
        merLicense.setLicenseId(null);
        merLicense.setMerId(newMerchant.getMerId());
        merLicenseService.save(merLicense);
        //4、新增法人信息
        MerLegalInfo merLegalInfo = merLegalInfoService.getOne(Wrappers.<MerLegalInfo>lambdaQuery().eq(MerLegalInfo::getMerId, merId));
        merLegalInfo.setLegalId(null);
        merLegalInfo.setMerId(newMerchant.getMerId());
        merLegalInfoService.save(merLegalInfo);
        //5、新增场地信息
        MerVenueInfo venueInfo = merVenueInfoService.getOne(Wrappers.<MerVenueInfo>lambdaQuery().eq(MerVenueInfo::getMerId, merId));
        venueInfo.setVenueId(null);
        venueInfo.setMerId(newMerchant.getMerId());
        merVenueInfoService.save(venueInfo);
        //6、生成审核记录表
        updateMerchantAuditStatus(MerchantAuditStatusDto.builder()
                .merId(newMerchant.getMerId())
                .auditStatus(CommonEnum.auditType.SUBMIT_INITIAL_REVIEW.name())
                .reexamineFlag(false)
                .submitPreliminaryReviewFlag(false)
                .build());
        //7、更新关联信息
        merchant.setReapplyRelatedMerId(newMerchant.getMerId());
        merMerchantService.updateById(merchant);
        //8、附件信息
        List<MerAttach> attachList = merAttachService.getLatestAttachByMerIdAndAttachType(merchant.getMerId(), attachTypeList);
        List<String> attachIds = attachList.stream().map(MerAttach::getAttachId).collect(Collectors.toList());
        //附件详情
        List<MerAttachValue> attachValues = merAttachValueService.list(Wrappers.<MerAttachValue>lambdaQuery().in(MerAttachValue::getAttachId, attachIds));
        Map<String, List<MerAttachValue>> attachValueMap = attachValues.stream().collect(Collectors.groupingBy(MerAttachValue::getAttachId));
        attachList.forEach(attach -> {
            MerAttach merAttach = new MerAttach();
            merAttach.setMerId(newMerchant.getMerId());
            merAttach.setConfigName(attach.getConfigName());
            merAttach.setConfigCode(attach.getConfigCode());
            merAttach.setAttachType(attach.getAttachType());
            merAttachService.save(merAttach);
            List<MerAttachValue> merAttachValues = attachValueMap.get(attach.getAttachId());
            if (CollectionUtils.isEmpty(merAttachValues)) {
                return;
            }
            merAttachValues.forEach(attachValue -> {
                MerAttachValue merAttachValue = new MerAttachValue();
                merAttachValue.setAttachId(merAttach.getAttachId());
                merAttachValue.setValValue(attachValue.getValValue());
                merAttachValueService.save(merAttachValue);
            });
        });
        return newMerchant;
    }


    private void saveRateInfo(List<MerchantRateDto> sourceInfoDto, String merId) {
        if (CollectionUtils.isEmpty(sourceInfoDto)) {
            throw BusinessException.businessOther("费率信息不存在，请确认");
        }
        sourceInfoDto.forEach(ValidationUtils::validate);
        //取出传入的数据中存在主键的
        List<String> rateInfoList = sourceInfoDto.stream()
                .map(MerchantRateDto::getMerRateId)
                .filter(StringUtils::hasText)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(rateInfoList)) {
            //删除传入的数据中没有的
            merMerchantRateManageService.remove(Wrappers.<MerMerchantRateManage>lambdaQuery().eq(MerMerchantRateManage::getMerId, merId).notIn(MerMerchantRateManage::getMerRateId, rateInfoList));
        }
        for (MerchantRateDto dto : sourceInfoDto) {
            MerMerchantRateManage rate = new MerMerchantRateManage();
            if (StringUtils.hasText(dto.getMerRateId())) {
                rate = merMerchantRateManageService.getById(dto.getMerRateId());
            }
            BeanUtils.copyPropertiesIgnoreNull(dto, rate);
            if (!StringUtils.hasText(dto.getMerId())) {
                rate.setMerId(merId);
            }
            merMerchantRateManageService.saveOrUpdate(rate);
            merMerchantRateManageDetailService.batchSaveOrUpdate(dto, rate.getMerRateId());
        }
    }

    private void saveCapitalOrder(List<MerMerchantCapitalOrderDto> capitalOrderDto, String merId) {
        if (CollectionUtils.isEmpty(capitalOrderDto)) {
            throw BusinessException.businessOther("资方顺位不存在，请确认");
        }
        capitalOrderDto.forEach(ValidationUtils::validate);
        //取出传入的数据中存在主键的
        List<String> capitalOrderList = capitalOrderDto.stream()
                .map(MerMerchantCapitalOrderDto::getCapitalId)
                .filter(StringUtils::hasText)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(capitalOrderList)) {
            //删除传入的数据中没有的
            List<MerMerchantCapitalOrder> list = merMerchantCapitalOrderService.list(Wrappers.<MerMerchantCapitalOrder>lambdaQuery()
                    .eq(MerMerchantCapitalOrder::getMerId, merId)
                    .notIn(MerMerchantCapitalOrder::getCapitalId, capitalOrderList));
            if (!CollectionUtils.isEmpty(list)) {
                list.forEach(item -> merMerchantCapitalOrderService.removeById(item.getCapitalId()));
            }
        }
        for (MerMerchantCapitalOrderDto dto : capitalOrderDto) {
            MerMerchantCapitalOrder capitalOrder = new MerMerchantCapitalOrder();
            if (StringUtils.hasText(dto.getCapitalId())) {
                capitalOrder = merMerchantCapitalOrderService.getById(dto.getCapitalId());
            }
            MerMerchantCapitalOrder oldDto = new MerMerchantCapitalOrder();
            BeanUtils.copyPropertiesIgnoreNull(capitalOrder, oldDto);
            BeanUtils.copyPropertiesIgnoreNull(dto, capitalOrder);
            merMerchantCapitalOrderService.saveOrUpdate(capitalOrder);
        }
    }

    private void saveBackCard(List<MerBackCardDto> bankCardDtos, String merId) {
        if (!StringUtils.hasText(merId)) {
            throw BusinessException.businessParamsNotExist("商户ID不能为空");
        }
        if (CollectionUtils.isEmpty(bankCardDtos)) {
            throw BusinessException.businessOther("收款卡不存在，请确认");
        }
        //除了自主支付，其余都需要校验非空
        bankCardDtos.forEach(item -> {
            //自主支付不校验必填项，其余必填项校验
            if (Objects.equals(CommonEnum.CardTypeEnum.SELF_PAYMENT.getCode(), item.getCardType())) {
                return;
            }
            //除了仅对私和卡类型为对私的 其余都需要校验联行号
            if (!Objects.equals("1", item.getPaymentPreference()) && !StringUtils.hasText(item.getCardPrcptcd()) && !Objects.equals(CommonEnum.CardTypeEnum.PRIVATE.name(),item.getCardType())) {
                throw BusinessException.businessOther("非仅对私卡片必须填写联行号");
            }

            ValidationUtils.validate(item);
        });
        // 处理需要删除的卡片
        List<String> existingCardIds = bankCardDtos.stream()
                .map(MerBackCardDto::getCardId)
                .filter(StringUtils::hasText)
                .collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(existingCardIds)) {
            List<MerBankCard> cardsToDelete = merBankCardService.list(
                    Wrappers.<MerBankCard>lambdaQuery()
                            .eq(MerBankCard::getMerId, merId)
                            .notIn(MerBankCard::getCardId, existingCardIds));

            if (!CollectionUtils.isEmpty(cardsToDelete)) {
                cardsToDelete.forEach(card -> merBankCardService.removeById(card.getCardId()));
            }
        } else {
            List<MerBankCard> cardsToDelete = merBankCardService.list(
                    Wrappers.<MerBankCard>lambdaQuery().eq(MerBankCard::getMerId, merId));

            if (!CollectionUtils.isEmpty(cardsToDelete)) {
                cardsToDelete.forEach(card -> merBankCardService.removeById(card.getCardId()));
            }
        }

        // 保存或更新卡片
        bankCardDtos.forEach(dto -> {
            MerBankCard bankCard = StringUtils.hasText(dto.getCardId())
                    ? merBankCardService.getById(dto.getCardId())
                    : new MerBankCard();

            MerBankCard oldCard = new MerBankCard();
            BeanUtils.copyPropertiesIgnoreNull(bankCard, oldCard);
            BeanUtils.copyPropertiesIgnoreNull(dto, bankCard);
            bankCard.setCardStatus(true);

            merBankCardService.saveOrUpdate(bankCard);
        });
    }


    private void saveInstallmentInfo(MerInstallmentInfoDto dto, String merId) {
        if (Objects.isNull(dto)) {
            throw BusinessException.businessParamsNotExist("分期信息不能为空");
        }
        ValidationUtils.validate(dto);

        MerInstallmentInfo installmentInfo = new MerInstallmentInfo();
        if (StringUtils.hasText(merId)) {
            MerInstallmentInfo old = merInstallmentInfoService.getOne(Wrappers.<MerInstallmentInfo>lambdaQuery().eq(MerInstallmentInfo::getMerId, dto.getMerId()));
            if (old != null) {
                installmentInfo = old;
            }
        }
        BeanUtils.copyPropertiesIgnoreNull(dto, installmentInfo);
        merInstallmentInfoService.saveOrUpdate(installmentInfo);
        merInstallmentInfoCompetitiveService.remove(Wrappers.<MerInstallmentInfoCompetitive>lambdaQuery().eq(MerInstallmentInfoCompetitive::getInstallmentId, installmentInfo.getInstallmentId()));
        merInstallmentInfoCompetitiveService.batchInsert(dto.getCompetitiveList(), installmentInfo.getInstallmentId());
    }

    private void saveMerBusinessFile(List<MerAttachDto> merAttachList, String merId) {
        if (CollectionUtils.isEmpty(merAttachList)) {
            return;
        }

        // 分布式锁Key：基于商户ID和固定业务标识，避免不同业务冲突
        String lockKey = Constant.COLLABORATION_APPLY_ATTACHMENT + merId;
        try {
            // 尝试加锁，最多等待3秒，锁自动释放时间10秒
            boolean locked = redisUtil.tryLock(lockKey, 2, TimeUnit.SECONDS);
            if (!locked) {
                throw BusinessException.businessOther("系统繁忙，请稍后重试");
            }

            // 加锁后重新查询数据，确保一致性
            List<MerAttach> list = merAttachService.list(Wrappers.<MerAttach>lambdaQuery()
                    .eq(MerAttach::getMerId, merId)
                    .eq(MerAttach::getAttachType, 3));
            if (CollectionUtils.isEmpty(list)) {
                log.warn("经营附件不存在，不更新附件明细信息");
                return;
            }

            // 构建附件映射并处理明细更新
            Map<String, MerAttach> merAttachMap = list.stream()
                    .collect(Collectors.toMap(MerAttach::getConfigCode, merAttach -> merAttach));

            merAttachList.forEach(item -> {
                MerAttach merAttach = merAttachMap.get(item.getConfigCode());
                if (merAttach != null) {
                    // 清除原有明细并插入新明细（事务性操作）
                    merAttachValueService.remove(Wrappers.<MerAttachValue>lambdaQuery()
                            .eq(MerAttachValue::getAttachId, merAttach.getAttachId()));

                    if (!CollectionUtils.isEmpty(item.getAttachResultList())) {
                        merAttachValueService.insertBatch(merAttach.getAttachId(), item.getAttachResultList());
                    }
                }
            });

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw BusinessException.businessOther("系统繁忙，请稍后重试");
        } finally {
            // 确保锁释放
            if (redisUtil.isLocked(lockKey)) {
                redisUtil.unlock(lockKey);
            }
        }
    }

    private void saveMerBusinessInfo(MerBusinessInfoDto dto, String merId) {
        if (Objects.isNull(dto)) {
            throw BusinessException.businessParamsNotExist("营业信息不能为空");
        }
        ValidationUtils.validate(dto);
        MerMerchant merchant = merMerchantService.getById(merId);
        if (Objects.isNull(merchant)) {
            throw BusinessException.businessParamsNotExist("商户不存在");
        }
        //根据场景分类校验不同场景下非空字段
        String sceneParentCategory = merchant.getSceneParentCategory();
        if (Objects.equals(sceneParentCategory, CommonEnum.sceneCategory.DJK.name())) {
            if (dto.getMerPhysicianNum() == null) {
                throw BusinessException.businessValidateError("医师数量不能为空");
            }
            if (dto.getMerOperationRoomNum() == null) {
                throw BusinessException.businessValidateError("手术室数量不能为空");
            }
            if (dto.getMonthlyCustomerFlow() == null) {
                throw BusinessException.businessValidateError("月度客流量不能为空");
            }
        } else {
            if (dto.getMerTeacherNum() == null) {
                throw BusinessException.businessValidateError("教师人数不能为空");
            }
            if (!StringUtils.hasText(dto.getCustomerPhone())) {
                throw BusinessException.businessValidateError("客服电话不能为空");
            }
            if (dto.getMonthlyCustomerNew() == null) {
                throw BusinessException.businessValidateError("月新客数不能为空");
            }
            if (!StringUtils.hasText(dto.getOnlinePlatform())) {
                throw BusinessException.businessValidateError("线上平台不能为空");
            }
        }
        MerRunInfo merRunInfo = merRunInfoService.getOne(Wrappers.<MerRunInfo>lambdaQuery().eq(MerRunInfo::getMerId, merId));
        if (Objects.isNull(merRunInfo)) {
            merRunInfo = new MerRunInfo();
            merRunInfo.setMerId(merId);
        }
        BeanUtils.copyPropertiesIgnoreNull(dto, merRunInfo);
        merRunInfoService.saveOrUpdate(merRunInfo);
    }


    private void saveAccountLicense(MerAccountLicenseDto accountLicenseDto) {
        if (accountLicenseDto == null) {
            throw BusinessException.businessParamsNotExist("开户信息不能为空");
        }
        if (!StringUtils.hasText(accountLicenseDto.getAcclImage())) {
            throw BusinessException.businessParamsNotExist("开户许可证图片不能为空");
        }
        ValidationUtils.validate(accountLicenseDto);
        if (StringUtils.hasText(accountLicenseDto.getAcclOpenDate())) {
            LocalDate startTime = LocalDate.parse(accountLicenseDto.getAcclOpenDate());
            LocalDate now = LocalDate.now();
            if (startTime.isAfter(now)) {
                throw BusinessException.businessValidateError("开户日期不能大于今天");
            }
        }
        MerAccountLicense accountLicense = merAccountLicenseService.getOne(Wrappers.<MerAccountLicense>lambdaQuery().eq(MerAccountLicense::getMerId, accountLicenseDto.getMerId()));
        if (accountLicense == null) {
            accountLicense = new MerAccountLicense();
        }
        BeanUtils.copyPropertiesIgnoreNull(accountLicenseDto, accountLicense);
        merAccountLicenseService.saveOrUpdate(accountLicense);
        //编辑开户许可证
        merAttachService.edit(accountLicenseDto.getMerId(), accountLicenseDto.getAcclImage(), CommonEnum.businessPhotoType.account_opening_license, 1);

    }

    private void saveVenueInfo(MerVenueInfoDto venueInfoDto) {
        if (venueInfoDto == null) {
            throw BusinessException.businessParamsNotExist("经营场所信息不能为空");
        }
        if (CollectionUtils.isEmpty(venueInfoDto.getVenueContract())) {
            throw BusinessException.businessParamsNotExist("租赁合同不能为空");
        }
        ValidationUtils.validate(venueInfoDto);
        if (venueInfoDto.getRentalType() == 1) {
            if (!StringUtils.hasText(venueInfoDto.getVenueDateStart())) {
                throw BusinessException.businessParamsNotExist("租赁期限开始日期不能为空");
            }
            if (!StringUtils.hasText(venueInfoDto.getVenueDateEnd())) {
                throw BusinessException.businessParamsNotExist("租赁期限结束日期不能为空");
            }
            if (StringUtils.hasText(venueInfoDto.getVenueDateStart())) {
                LocalDate startTime = LocalDate.parse(venueInfoDto.getVenueDateStart());
                LocalDate now = LocalDate.now();
                if (startTime.isAfter(now)) {
                    throw BusinessException.businessValidateError("租赁期限开始日期不能大于今天");
                }
            }
            if (StringUtils.hasText(venueInfoDto.getVenueDateEnd()) && !Objects.equals("长期", venueInfoDto.getVenueDateEnd())) {
                LocalDate endTime = LocalDate.parse(venueInfoDto.getVenueDateEnd());
                LocalDate now = LocalDate.now();
                if (endTime.isBefore(now)) {
                    throw BusinessException.businessValidateError("租赁期限结束日期不能小于今天");
                }
            }
        }
        MerVenueInfo merVenueInfo = merVenueInfoService.getOne(Wrappers.<MerVenueInfo>lambdaQuery().eq(MerVenueInfo::getMerId, venueInfoDto.getMerId()));
        if (merVenueInfo == null) {
            merVenueInfo = new MerVenueInfo();
        }
        BeanUtils.copyPropertiesIgnoreNull(venueInfoDto, merVenueInfo);
        merVenueInfoService.saveOrUpdate(merVenueInfo);
        //编辑租赁合同附件
        List<String> venueContract = venueInfoDto.getVenueContract();
        merAttachService.batchEdit(venueInfoDto.getMerId(), venueContract, CommonEnum.businessPhotoType.lease_agreement, 1);

    }

    private void saveMedicalLicense(MedicalLicenseDto dto) {
        if (dto == null) {
            return;
        }
        if (!StringUtils.hasText(dto.getMedlImage())) {
            throw BusinessException.businessParamsNotExist("医疗许可证图片地址不能为空");
        }
        MerMerchant merchant = merMerchantService.getById(dto.getMerId());
        if (Objects.isNull(merchant)) {
            throw BusinessException.businessParamsNotExist("商户不存在");
        }
        if (Objects.equals(merchant.getSceneParentCategory(), CommonEnum.sceneCategory.JY.name())) {
            return;
        }
        if (Objects.equals(merchant.getSceneParentCategory(), CommonEnum.sceneCategory.DJK.name())) {
            ValidationUtils.validate(dto);
            //根据许可证类型补充校验
            if (dto.getLicenseType() == 1) {
                if (dto.getMedlType() == null) {
                    throw BusinessException.businessParamsNotExist("商户类型不能为空");
                }
                if (!StringUtils.hasText(dto.getMedlPrincipal())) {
                    throw BusinessException.businessParamsNotExist("主要负责人不能为空");
                }
            }
            if (StringUtils.hasText(dto.getMedlValidateStart())) {
                LocalDate startTime = LocalDate.parse(dto.getMedlValidateStart());
                LocalDate now = LocalDate.now();
                if (startTime.isAfter(now)) {
                    throw BusinessException.businessValidateError("执照有效期开始日期不能大于今天");
                }
            }
            if (StringUtils.hasText(dto.getMedlValidateEnd()) && !Objects.equals("长期", dto.getMedlValidateEnd())) {
                LocalDate endTime = LocalDate.parse(dto.getMedlValidateEnd());
                LocalDate now = LocalDate.now();
                if (endTime.isBefore(now)) {
                    throw BusinessException.businessValidateError("执照有效期结束日期不能小于今天");
                }
            }
        }
        MerMedicalLicense merMedicalLicense = merMedicalLicenseService.getOne(Wrappers.<MerMedicalLicense>lambdaQuery().eq(MerMedicalLicense::getMerId, dto.getMerId()));
        if (merMedicalLicense == null) {
            merMedicalLicense = new MerMedicalLicense();
        }
        BeanUtils.copyPropertiesIgnoreNull(dto, merMedicalLicense);
        merMedicalLicenseService.saveOrUpdate(merMedicalLicense);
        //医疗许可证图片地址
        merAttachService.edit(dto.getMerId(), dto.getMedlImage(), CommonEnum.businessPhotoType.practice_license, 1);
    }


    /**
     * 注册资本转换  金额数字+1个空格+万+货币单位  例如： 3000 万人民币 转成3000
     *
     * @param amount
     * @return
     */
    public String conversionAmount(String amount) {
        Pattern pattern = Pattern.compile("(\\d+)");
        Matcher matcher = pattern.matcher(amount);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    public static String dateFormatConversion(String dateStr) {
        if (!StringUtils.hasText(dateStr)) {
            return "";
        }
        if (Objects.equals("长期", dateStr)) {
            return dateStr;
        }
        // 定义输入格式
        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        // 解析成 LocalDate
        LocalDate localDate = LocalDate.parse(dateStr, inputFormatter);
        // 定义输出格式
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return localDate.format(outputFormatter);
    }

    /**
     * 根据角色编码列表获取用户列表
     * @param roleCodeList  角色编码列表
     * @return  用户列表
     */
    public List<UserDto> getAccountListByRoleId(List<String> roleCodeList) {
        Result<List<Integer>> userResult = remoteRoleService.getUserByRoleCodes(roleCodeList, CommonConstant.INNER);
        List<Integer> userIdList = userResult.getData();
        Result<List<UserDto>> userDtoResult = remoteUserService.queryUserByIds(userIdList, CommonConstant.INNER);
        return userDtoResult.getData();
    }
}
